home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet internetowy / Rozne / HTTrack 3.40-2 / httrack-3.40-2.exe / {app} / src / htscore.c < prev    next >
C/C++ Source or Header  |  2006-01-21  |  121KB  |  3,783 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: Main source                                            */
  34. /* Author: Xavier Roche                                         */
  35. /* ------------------------------------------------------------ */
  36.  
  37. /* Internal engine bytecode */
  38. #define HTS_INTERNAL_BYTECODE
  39.  
  40. #ifndef  _WIN32_WCE
  41. #include <fcntl.h>
  42. #endif
  43. #include <ctype.h>
  44.  
  45. /* File defs */
  46. #include "htscore.h"
  47.  
  48. /* specific definitions */
  49. #include "htsbase.h"
  50. #include "htsnet.h"
  51. #include "htsbauth.h"
  52. #include "htsmd5.h"
  53. #include "htsindex.h"
  54.  
  55. /* external modules */
  56. #include "htsmodules.h"
  57.  
  58. // htswrap_add
  59. #include "htswrap.h"
  60.  
  61. // parser
  62. #include "htsparse.h"
  63.  
  64. /* Cache */
  65. #include "htszlib.h"
  66.  
  67.  
  68. /* END specific definitions */
  69.  
  70.  
  71. /* HTML parsing */
  72. #if HTS_ANALYSTE
  73.  
  74. t_hts_htmlcheck_init    hts_htmlcheck_init = NULL;
  75. t_hts_htmlcheck_uninit  hts_htmlcheck_uninit = NULL;
  76. t_hts_htmlcheck_start   hts_htmlcheck_start = NULL;
  77. t_hts_htmlcheck_end     hts_htmlcheck_end = NULL;
  78. t_hts_htmlcheck_chopt   hts_htmlcheck_chopt = NULL;
  79. t_hts_htmlcheck_process hts_htmlcheck_preprocess = NULL;
  80. t_hts_htmlcheck_process hts_htmlcheck_postprocess = NULL;
  81. t_hts_htmlcheck         hts_htmlcheck = NULL;
  82. t_hts_htmlcheck_query   hts_htmlcheck_query = NULL;
  83. t_hts_htmlcheck_query2  hts_htmlcheck_query2 = NULL;
  84. t_hts_htmlcheck_query3  hts_htmlcheck_query3 = NULL;
  85. t_hts_htmlcheck_loop    hts_htmlcheck_loop = NULL;
  86. t_hts_htmlcheck_check   hts_htmlcheck_check = NULL;
  87. t_hts_htmlcheck_check_mime hts_htmlcheck_check_mime = NULL;
  88. t_hts_htmlcheck_pause   hts_htmlcheck_pause = NULL;
  89. t_hts_htmlcheck_filesave       hts_htmlcheck_filesave = NULL;
  90. t_hts_htmlcheck_filesave2      hts_htmlcheck_filesave2 = NULL;
  91. t_hts_htmlcheck_linkdetected   hts_htmlcheck_linkdetected = NULL;
  92. t_hts_htmlcheck_linkdetected2  hts_htmlcheck_linkdetected2 = NULL;
  93. t_hts_htmlcheck_xfrstatus hts_htmlcheck_xfrstatus = NULL;
  94. t_hts_htmlcheck_savename  hts_htmlcheck_savename = NULL;
  95. t_hts_htmlcheck_sendhead  hts_htmlcheck_sendhead = NULL;
  96. t_hts_htmlcheck_receivehead  hts_htmlcheck_receivehead = NULL;
  97.  
  98. extern void set_wrappers(void);
  99.  
  100. char _hts_errmsg[1100]="";
  101. int _hts_in_html_parsing=0;
  102. int _hts_in_html_done=0;  // % done
  103. int _hts_in_html_poll=0;  // parsing
  104. int _hts_setpause=0;
  105. //httrackp* _hts_setopt=NULL;
  106. char** _hts_addurl=NULL;
  107.  
  108. /* external modules */
  109. extern int hts_parse_externals(htsmoduleStruct* str);
  110. extern void htspe_init(void);
  111.  
  112. //
  113. int _hts_cancel=0;
  114. #endif
  115.  
  116.  
  117.  
  118. int exit_xh;          /* quick exit (fatal error or interrupt) */
  119.  
  120. /* debug */
  121. #if DEBUG_SHOWTYPES
  122. char REG[32768]="\n";
  123. #endif
  124. #if NSDEBUG
  125. int nsocDEBUG=0;
  126. #endif
  127.  
  128. //
  129. #define _CLRSCR printf("\33[m\33[2J");
  130. #define _GOTOXY(X,Y) printf("\33[" X ";" Y "f");
  131.  
  132. #if DEBUG_CHECKINT
  133.  #define _CHECKINT_FAIL(a) printf("\n%s\n",a); fflush(stdout); exit(1);
  134.  #define _CHECKINT(obj_ptr,message) \
  135.    if (obj_ptr) {\
  136.      if (( * ((char*) (obj_ptr)) != 0) || ( * ((char*) (((char*) (obj_ptr)) + sizeof(*(obj_ptr))-1)) != 0)) {\
  137.        char msg[1100];\
  138.        if (( * ((char*) (obj_ptr)) != 0) && ( * ((char*) (((char*) (obj_ptr)) + sizeof(*(obj_ptr))-1)) != 0))\
  139.          sprintf(msg,"* PANIC: Integrity error (structure crushed)  in: %s",message);\
  140.        else if ( * ((char*) (obj_ptr)) != 0)\
  141.          sprintf(msg,"* PANIC: Integrity error (start of structure) in: %s",message);\
  142.        else\
  143.          sprintf(msg,"* PANIC: Integrity error (end of structure)   in: %s",message);\
  144.        _CHECKINT_FAIL(msg);\
  145.      }\
  146.    } else {\
  147.      char msg[1100];\
  148.      sprintf(msg,"* PANIC: NULL pointer in: %s",message);\
  149.      _CHECKINT_FAIL(msg);\
  150.    }
  151. #endif
  152.  
  153. #if DEBUG_HASH
  154.   // longest hash chain?
  155.   int longest_hash[3]={0,0,0},hashnumber=0;
  156. #endif
  157.  
  158. // demande d'interaction avec le shell
  159. #if HTS_ANALYSTE
  160. char HTbuff[2048];
  161. #endif
  162.  
  163.  
  164.  
  165. // DΘbut de httpmirror, routines annexes
  166.  
  167. // version 1 pour httpmirror
  168. // flusher si on doit lire peu α peu le fichier
  169. #define test_flush if (opt.flush) { fflush(opt.log); fflush(opt.errlog); }
  170.  
  171. // pour allΘger la syntaxe, des raccourcis sont crΘΘs
  172. #define urladr   (liens[ptr]->adr)
  173. #define urlfil   (liens[ptr]->fil)
  174. #define savename (liens[ptr]->sav)
  175. //#define level    (liens[ptr]->depth)
  176.  
  177. // au cas o∙ nous devons quitter rapidement xhttpmirror (plus de mΘmoire, etc)
  178. // note: partir de liens_max.. vers 0.. sinon erreur de violation de mΘmoire: les liens suivants
  179. // ne sont plus α nous.. agh! [dur celui-lα]
  180. #if HTS_ANALYSTE
  181. #define HTMLCHECK_UNINIT { \
  182. if ( (opt.debug>0) && (opt.log!=NULL) ) { \
  183. fspc(opt.log,"info"); fprintf(opt.log,"engine: end"LF); \
  184. } \
  185. if (hts_htmlcheck_end != NULL) { \
  186.   hts_htmlcheck_end(); \
  187. } \
  188. }
  189. #else
  190.  #define HTMLCHECK_UNINIT 
  191. #endif
  192.  
  193. #define XH_extuninit do { \
  194.   int i; \
  195.   HTMLCHECK_UNINIT \
  196.   if (liens!=NULL) { \
  197.   for(i=lien_max-1;i>=0;i--) { \
  198.   if (liens[i]) { \
  199.   if (liens[i]->firstblock==1) { \
  200.   freet(liens[i]); \
  201.   liens[i]=NULL; \
  202.   } \
  203.   } \
  204.   } \
  205.   freet(liens); \
  206.   liens=NULL; \
  207.   } \
  208.   if (filters && filters[0]) { \
  209.   freet(filters[0]); filters[0]=NULL; \
  210.   } \
  211.   if (filters) { \
  212.   freet(filters); filters=NULL; \
  213.   } \
  214.   back_delete_all(&opt,&cache,sback); \
  215.   back_free(&sback); \
  216.   checkrobots_free(&robots);\
  217.   if (cache.use) { freet(cache.use); cache.use=NULL; } \
  218.   if (cache.dat) { fclose(cache.dat); cache.dat=NULL; }  \
  219.   if (cache.ndx) { fclose(cache.ndx); cache.ndx=NULL; } \
  220.   if (cache.zipOutput) { \
  221.     zipClose(cache.zipOutput, "Created by HTTrack Website Copier/"HTTRACK_VERSION); \
  222.     cache.zipOutput = NULL; \
  223.   } \
  224.   if (cache.zipInput) { \
  225.     unzClose(cache.zipInput); \
  226.     cache.zipInput = NULL; \
  227.   } \
  228.   if (cache.olddat) { fclose(cache.olddat); cache.olddat=NULL; } \
  229.   if (cache.lst) { fclose(cache.lst); cache.lst=NULL; } \
  230.   if (cache.txt) { fclose(cache.txt); cache.txt=NULL; } \
  231.   if (opt.log) fflush(opt.log); \
  232.   if (opt.errlog) fflush(opt.errlog);\
  233.   if (makestat_fp) { fclose(makestat_fp); makestat_fp=NULL; } \
  234.   if (maketrack_fp){ fclose(maketrack_fp); maketrack_fp=NULL; } \
  235.   if (opt.accept_cookie) cookie_save(opt.cookie,fconcat(opt.path_log,"cookies.txt")); \
  236.   if (makeindex_fp) { fclose(makeindex_fp); makeindex_fp=NULL; } \
  237.   if (cache_hashtable) { inthash_delete(&cache_hashtable); } \
  238.   if (cache_tests)     { inthash_delete(&cache_tests); } \
  239.   if (template_header) { freet(template_header); template_header=NULL; } \
  240.   if (template_body)   { freet(template_body); template_body=NULL; } \
  241.   if (template_footer) { freet(template_footer); template_footer=NULL; } \
  242.   clearCallbacks(&opt.state.callbacks); \
  243.   /*structcheck_init(-1);*/ \
  244. } while(0)
  245. #define XH_uninit do { XH_extuninit; if (r.adr) { freet(r.adr); r.adr=NULL; } } while(0)
  246.  
  247. // Enregistrement d'un lien:
  248. // on calcule la taille nΘcessaire: taille des 3 chaεnes α stocker (taille forcΘe paire, plus 2 octets de sΘcuritΘ)
  249. // puis on vΘrifie qu'on a assez de marge dans le buffer - sinon on en rΘalloue un autre
  250. // enfin on Θcrit α l'adresse courante du buffer, qu'on incrΘmente. on dΘcrΘmente la taille dispo d'autant ensuite
  251. // codebase: si non nul et si .class stockee on le note pour chemin primaire pour classes
  252. // FA,FS: former_adr et former_fil, lien original
  253. #define liens_record_sav_len(A) 
  254.  
  255. #define liens_record(A,F,S,FA,FF,NORM) { \
  256. int notecode=0; \
  257. int lienurl_len=((sizeof(lien_url)+HTS_ALIGN-1)/HTS_ALIGN)*HTS_ALIGN,\
  258.   adr_len=strlen(A),\
  259.   fil_len=strlen(F),\
  260.   sav_len=strlen(S),\
  261.   cod_len=0,\
  262.   former_adr_len=strlen(FA),\
  263.   former_fil_len=strlen(FF); \
  264. if (former_adr_len>0) {\
  265.   former_adr_len=(former_adr_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; \
  266.   former_fil_len=(former_fil_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; \
  267. } else former_adr_len=former_fil_len=0;\
  268. if (strlen(F)>6) if (strnotempty(codebase)) if (strfield(F+strlen(F)-6,".class")) { notecode=1; \
  269. cod_len=strlen(codebase); cod_len=(cod_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; } \
  270. adr_len=(adr_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; fil_len=(fil_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; sav_len=(sav_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; \
  271. if ((int) lien_size < (int) (adr_len+fil_len+sav_len+cod_len+former_adr_len+former_fil_len+lienurl_len)) { \
  272. lien_buffer=(char*) ((void*) calloct(add_tab_alloc,1)); \
  273. lien_size=add_tab_alloc; \
  274. if (lien_buffer!=NULL) { \
  275. liens[lien_tot]=(lien_url*) (void*) lien_buffer; lien_buffer+=lienurl_len; lien_size-=lienurl_len; \
  276. liens[lien_tot]->firstblock=1; \
  277. } \
  278. } else { \
  279. liens[lien_tot]=(lien_url*) (void*) lien_buffer; lien_buffer+=lienurl_len; lien_size-=lienurl_len; \
  280. liens[lien_tot]->firstblock=0; \
  281. } \
  282. if (liens[lien_tot]!=NULL) { \
  283. liens[lien_tot]->adr=lien_buffer; lien_buffer+=adr_len; lien_size-=adr_len; \
  284. liens[lien_tot]->fil=lien_buffer; lien_buffer+=fil_len; lien_size-=fil_len; \
  285. liens[lien_tot]->sav=lien_buffer; lien_buffer+=sav_len; lien_size-=sav_len; \
  286. liens[lien_tot]->cod=NULL; \
  287. if (notecode) { liens[lien_tot]->cod=lien_buffer; lien_buffer+=cod_len; lien_size-=cod_len; strcpybuff(liens[lien_tot]->cod,codebase); } \
  288. if (former_adr_len>0) {\
  289. liens[lien_tot]->former_adr=lien_buffer; lien_buffer+=former_adr_len; lien_size-=former_adr_len; \
  290. liens[lien_tot]->former_fil=lien_buffer; lien_buffer+=former_fil_len; lien_size-=former_fil_len; \
  291. strcpybuff(liens[lien_tot]->former_adr,FA); \
  292. strcpybuff(liens[lien_tot]->former_fil,FF); \
  293. }\
  294. strcpybuff(liens[lien_tot]->adr,A); \
  295. strcpybuff(liens[lien_tot]->fil,F); \
  296. strcpybuff(liens[lien_tot]->sav,S); \
  297. liens_record_sav_len(liens[lien_tot]); \
  298. hash_write(hashptr,lien_tot,NORM);  \
  299. } \
  300. }
  301.  
  302.  
  303. #define HT_INDEX_END do { \
  304. if (!makeindex_done) { \
  305. if (makeindex_fp) { \
  306.   char BIGSTK tempo[1024]; \
  307.   if (makeindex_links == 1) { \
  308.     sprintf(tempo,"<meta HTTP-EQUIV=\"Refresh\" CONTENT=\"0; URL=%s\">"CRLF,makeindex_firstlink); \
  309.   } else \
  310.     tempo[0]='\0'; \
  311.   fprintf(makeindex_fp,template_footer, \
  312.     "<!-- Mirror and index made by HTTrack Website Copier/"HTTRACK_VERSION" "HTTRACK_AFF_AUTHORS" -->", \
  313.     tempo \
  314.     ); \
  315.   fflush(makeindex_fp); \
  316.   fclose(makeindex_fp);  /* α ne pas oublier sinon on passe une nuit blanche */  \
  317.   makeindex_fp=NULL; \
  318.   usercommand(&opt,0,NULL,fconcat(opt.path_html,"index.html"),"","");  \
  319. } \
  320. } \
  321. makeindex_done=1;    /* ok c'est fait */  \
  322. } while(0)
  323.  
  324.  
  325.  
  326.  
  327. // DΘbut de httpmirror, robot
  328. // url1 peut Ωtre multiple
  329. int httpmirror(char* url1,httrackp* ptropt) {
  330.   httrackp BIGSTK opt;         // structure d'options
  331.   char* primary=NULL;          // premiΦre page, contenant les liens α scanner
  332.   int lien_tot=0;              // nombre de liens pour le moment
  333.   lien_url** liens=NULL;       // les pointeurs sur les liens
  334.   hash_struct hash;            // systΦme de hachage, accΘlΦre la recherche dans les liens
  335.   hash_struct* hashptr = &hash;
  336.   t_cookie BIGSTK cookie;             // gestion des cookies
  337.   int lien_max=0;
  338.   int lien_size=0;        // octets restants dans buffer liens dispo
  339.   char* lien_buffer=NULL; // buffer liens actuel
  340.   int add_tab_alloc=256000;    // +256K de liens α chaque fois
  341.   //char* tab_alloc=NULL;
  342.   int ptr;             // pointeur actuel sur les liens
  343.   //
  344.   int numero_passe=0;  // deux passes pour html puis images
  345.   struct_back* sback=NULL;
  346.   htsblk BIGSTK r;            // retour de certaines fonctions
  347.   TStamp lastime=0;    // pour affichage infos de tmp en tmp
  348.   // pour les stats, nombre de fichiers & octets Θcrits
  349.   LLint stat_fragment=0;  // pour la fragmentation
  350.   //TStamp istat_timestart;   // dΘpart pour calcul instantannΘ
  351.   //
  352.   TStamp last_info_shell=0;
  353.   int info_shell=0;
  354.   // filtres
  355.   char** filters = NULL;
  356.   //int filter_max=0;
  357.   int filptr=0;
  358.   //
  359.   int makeindex_done=0;  // lorsque l'index sera fait
  360.   FILE* makeindex_fp=NULL;
  361.   int makeindex_links=0;
  362.   char BIGSTK makeindex_firstlink[HTS_URLMAXSIZE*2];
  363.   // statistiques (mode #Z)
  364.   FILE* makestat_fp=NULL;    // fichier de stats taux transfert
  365.   FILE* maketrack_fp=NULL;   // idem pour le tracking
  366.   TStamp makestat_time=0;    // attente (secondes)
  367.   LLint makestat_total=0;    // repΦre du nombre d'octets transfΘrΘs depuis denriΦre stat
  368.   int makestat_lnk=0;        // idem, pour le nombre de liens
  369.   //
  370.   char BIGSTK codebase[HTS_URLMAXSIZE*2];  // base pour applet java
  371.   char BIGSTK base[HTS_URLMAXSIZE*2];      // base pour les autres fichiers
  372.   //
  373.   cache_back BIGSTK cache;
  374.   robots_wizard BIGSTK robots;    // gestion robots.txt
  375.   inthash cache_hashtable=NULL;
  376.   inthash cache_tests=NULL;
  377.   int cache_hash_size=0;
  378.   //
  379.   char *template_header=NULL,*template_body=NULL,*template_footer=NULL;
  380.   //
  381.   opt = *ptropt;
  382.   //
  383.   codebase[0]='\0'; base[0]='\0';
  384.   //
  385.   cookie.auth.next=NULL;
  386.   cookie.auth.auth[0]=cookie.auth.prefix[0]='\0';
  387.   //
  388.  
  389.   // noter heure actuelle de dΘpart en secondes
  390.   memset(&HTS_STAT, 0, sizeof(HTS_STAT));
  391.   HTS_STAT.stat_timestart=time_local();
  392.   //istat_timestart=stat_timestart;
  393.   HTS_STAT.istat_timestart[0]=HTS_STAT.istat_timestart[1]=mtime_local();
  394.   /* reset stats */
  395.   HTS_STAT.HTS_TOTAL_RECV=0;
  396.   HTS_STAT.istat_bytes[0]=HTS_STAT.istat_bytes[1]=0;
  397.   /*
  398.   if (opt.aff_progress)
  399.     lastime=HTS_STAT.stat_timestart;
  400.     */
  401.   if (opt.shell) {
  402.     last_info_shell=HTS_STAT.stat_timestart;
  403.   }
  404.   if ((opt.makestat) || (opt.maketrack)){
  405.     makestat_time=HTS_STAT.stat_timestart;
  406.   }
  407.   // initialiser compteur erreurs
  408.   fspc(NULL,NULL);
  409.  
  410.   // init external modules
  411.   htspe_init();
  412.  
  413.   // initialiser cookie
  414.   if (opt.accept_cookie) {
  415.     opt.cookie=&cookie;
  416.     cookie.max_len=30000;       // max len
  417.     strcpybuff(cookie.data,"");
  418.     // Charger cookies.txt par dΘfaut ou cookies.txt du miroir
  419.     cookie_load(opt.cookie,opt.path_log,"cookies.txt");
  420.     cookie_load(opt.cookie,"","cookies.txt");
  421.   } else
  422.     opt.cookie=NULL;
  423.  
  424.   // initialiser exit_xh
  425.   exit_xh=0;          // sortir prΘmaturΘment (var globale)
  426.  
  427.   // initialiser usercommand
  428.   usercommand(&opt,opt.sys_com_exec,opt.sys_com,"","","");
  429.  
  430.   // initialiser structcheck
  431.   // structcheck_init(1);
  432.  
  433.   // initialiser tableau options accessible par d'autres fonctions (signal)
  434.   hts_declareoptbuffer(&opt);
  435.  
  436.   // initialiser verif_backblue
  437.   verif_backblue(&opt,NULL);
  438.   verif_external(0,0);
  439.   verif_external(1,0);
  440.  
  441.   // et templates html
  442.   template_header=readfile_or(fconcat(opt.path_bin,"templates/index-header.html"),HTS_INDEX_HEADER);
  443.   template_body=readfile_or(fconcat(opt.path_bin,"templates/index-body.html"),HTS_INDEX_BODY);
  444.   template_footer=readfile_or(fconcat(opt.path_bin,"templates/index-footer.html"),HTS_INDEX_FOOTER);
  445.  
  446.   // initialiser mimedefs
  447.   get_userhttptype(1,opt.mimedefs,NULL);
  448.  
  449.   // Initialiser indexation
  450.   if (opt.kindex)
  451.     index_init(opt.path_html);
  452.  
  453.   // effacer bloc cache
  454.   memset(&cache, 0, sizeof(cache_back));
  455.   cache.type=opt.cache;  // cache?
  456.   cache.errlog=opt.errlog;  // err log?
  457.   cache.ptr_ant=cache.ptr_last=0;   // pointeur pour anticiper
  458.  
  459.   // initialiser hash cache
  460.   if (!cache_hash_size) 
  461.     cache_hash_size=HTS_HASH_SIZE;
  462.   cache_hashtable=inthash_new(cache_hash_size);
  463.   cache_tests=inthash_new(cache_hash_size);
  464.   if (cache_hashtable==NULL || cache_tests==NULL) {
  465.     printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  466.     filters[0]=NULL;    // uniquement a cause du warning de XH_extuninit
  467.     XH_extuninit;
  468.     return 0;
  469.   }
  470.   inthash_value_is_malloc(cache_tests, 1);     /* malloc */
  471.   cache.hashtable=(void*)cache_hashtable;      /* copy backcache hash */
  472.   cache.cached_tests=(void*)cache_tests;      /* copy of cache_tests */
  473.  
  474.   // initialiser cache DNS
  475.   _hts_lockdns(-999);
  476.   
  477.   // robots.txt
  478.   strcpybuff(robots.adr,"!");    // dummy
  479.   robots.token[0]='\0';
  480.   robots.next=NULL;          // suivant
  481.   opt.robotsptr = &robots;
  482.   
  483.   // effacer filters
  484.   opt.maxfilter = maximum(opt.maxfilter, 128);
  485.   if (filters_init(&filters, opt.maxfilter, 0) == 0) {
  486.     printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  487.     XH_extuninit;
  488.     return 0;
  489.   }
  490.   opt.filters.filters=&filters;
  491.   //
  492.   opt.filters.filptr=&filptr;
  493.   //opt.filters.filter_max=&filter_max;
  494.   
  495.   // hash table
  496.   opt.hash = &hash;
  497.  
  498.   // tableau de pointeurs sur les liens
  499.   lien_max=maximum(opt.maxlink,32);
  500.   liens=(lien_url**) malloct(lien_max*sizeof(lien_url*));   // tableau de pointeurs sur les liens
  501.   if (liens==NULL) {
  502.     printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  503.     //XH_uninit;
  504.     return 0;
  505.   } else {
  506.     int i;
  507.     for(i=0;i<lien_max;i++) {
  508.       liens[i]=NULL;     
  509.     }
  510.   }
  511.   // initialiser ptr et lien_tot
  512.   ptr=0;
  513.   lien_tot=0;
  514.   // initialiser hachage
  515.   {
  516.     int i;
  517.     for(i=0;i<HTS_HASH_SIZE;i++)
  518.       hash.hash[0][i]=hash.hash[1][i]=hash.hash[2][i] = -1;    // pas d'entrΘes
  519.     hash.liens = liens;
  520.     hash.max_lien=0;
  521.   }
  522.   
  523.   // copier adresse(s) dans liste des adresses
  524.   {
  525.     char *a=url1;
  526.     int primary_len=8192;
  527.     if (strnotempty(opt.filelist)) {
  528.       primary_len+=max(0,fsize(opt.filelist)*2);
  529.     }
  530.     primary_len+=strlen(url1)*2;
  531.  
  532.     // crΘation de la premiΦre page, qui contient les liens de base α scanner
  533.     // c'est plus propre et plus logique que d'entrer α la main les liens dans la pile
  534.     // on bΘnΘficie ainsi des vΘrifications et des tests du robot pour les liens "primaires"
  535.     primary=(char*) malloct(primary_len); 
  536.     if (primary) {
  537.       primary[0]='\0';
  538.     } else {
  539.       printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  540.       XH_extuninit;
  541.       return 0;
  542.     }
  543.     
  544.     while(*a) {
  545.       int i;
  546.       int joker=0;
  547.  
  548.       // vΘrifier qu'il n'y a pas de * dans l'url
  549.       if (*a=='+')
  550.         joker=1;
  551.       else if (*a=='-')
  552.         joker=1;
  553.       
  554.       if (joker) {    // joker ou filters
  555.         //char* p;
  556.         char BIGSTK tempo[HTS_URLMAXSIZE*2];
  557.         int type; int plus=0;
  558.  
  559.         // noter joker (dans b)
  560.         if (*a=='+') {  // champ +
  561.           type=1; plus=1; a++;
  562.         } else if (*a=='-') {  // champ forbidden[]
  563.           type=0; a++;
  564.         } else {  // champ + avec joker sans doute
  565.           type=1;
  566.         }
  567.  
  568.         // recopier prochaine chaine (+ ou -)
  569.         i=0;
  570.         while((*a!=0) && (!isspace((unsigned char)*a))) { tempo[i++]=*a; a++; }  
  571.         tempo[i++]='\0';
  572.         while(isspace((unsigned char)*a)) { a++; }
  573.  
  574.         // sauter les + sans rien aprΦs..
  575.         if (strnotempty(tempo)) {
  576.           if ((plus==0) && (type==1)) {  // implicite: *www.edf.fr par exemple
  577.             if (tempo[strlen(tempo)-1]!='*') {
  578.               strcatbuff(tempo,"*");  // ajouter un *
  579.             }
  580.           }
  581.           if (type)
  582.             strcpybuff(filters[filptr],"+");
  583.           else
  584.             strcpybuff(filters[filptr],"-");
  585.           strcatbuff(filters[filptr],tempo);
  586.           filptr++;
  587.           
  588.           /* sanity check */
  589.           if (filptr + 1 >= opt.maxfilter) {
  590.             opt.maxfilter += HTS_FILTERSINC;
  591.             if (filters_init(&filters, opt.maxfilter, HTS_FILTERSINC) == 0) {
  592.               printf("PANIC! : Too many filters : >%d [%d]\n",filptr,__LINE__);
  593.               if (opt.errlog) {
  594.                 fprintf(opt.errlog,LF"Too many filters, giving up..(>%d)"LF,filptr);
  595.                 fprintf(opt.errlog,"To avoid that: use #F option for more filters (example: -#F5000)"LF);
  596.                 test_flush;
  597.               }
  598.               XH_extuninit;
  599.               return 0;
  600.             }
  601.             //opt.filters.filters=filters;
  602.           }
  603.  
  604.         }
  605.         
  606.       } else {    // adresse normale
  607.         char BIGSTK url[HTS_URLMAXSIZE*2];
  608.         // prochaine adresse
  609.         i=0;
  610.         while((*a!=0) && (!isspace((unsigned char)*a))) { url[i++]=*a; a++; }  
  611.         while(isspace((unsigned char)*a)) { a++; }
  612.         url[i++]='\0';
  613.  
  614.         //strcatbuff(primary,"<PRIMARY=\"");
  615.         if (strstr(url,":/")==NULL)
  616.           strcatbuff(primary,"http://");
  617.         strcatbuff(primary,url);
  618.         //strcatbuff(primary,"\">");
  619.         strcatbuff(primary,"\n");
  620.       }
  621.     }  // while
  622.  
  623.     /* load URL file list */
  624.     /* OPTIMIZED for fast load */
  625.     if (strnotempty(opt.filelist)) {
  626.       char* filelist_buff=NULL;
  627.       INTsys filelist_sz=fsize(opt.filelist);
  628.       if (filelist_sz>0) {
  629.         FILE* fp=fopen(opt.filelist,"rb");
  630.         if (fp) {
  631.           filelist_buff=malloct(filelist_sz + 2);
  632.           if (filelist_buff) {
  633.             if ((INTsys)fread(filelist_buff,1,filelist_sz,fp) != filelist_sz) {
  634.               freet(filelist_buff);
  635.               filelist_buff=NULL;
  636.             } else {
  637.               *(filelist_buff + filelist_sz) = '\0';
  638.             }
  639.           }
  640.           fclose(fp);
  641.         }
  642.       }
  643.       
  644.       if (filelist_buff) {
  645.         int filelist_ptr=0;
  646.         int n=0;
  647.         char BIGSTK line[HTS_URLMAXSIZE*2];
  648.         char* primary_ptr = primary + strlen(primary);
  649.         while( filelist_ptr < filelist_sz ) {
  650.           int count=binput(filelist_buff+filelist_ptr,line,HTS_URLMAXSIZE);
  651.           filelist_ptr+=count;
  652.           if (count && line[0]) {
  653.             n++;
  654.             if (strstr(line,":/")==NULL) {
  655.               strcpybuff(primary_ptr, "http://");
  656.               primary_ptr += strlen(primary_ptr);
  657.             }
  658.             strcpybuff(primary_ptr, line);
  659.             primary_ptr += strlen(primary_ptr);
  660.             strcpybuff(primary_ptr, "\n");
  661.             primary_ptr += 1;
  662.           }
  663.         }
  664.         // fclose(fp);
  665.         if (opt.log!=NULL) {
  666.           fspc(opt.log,"info"); fprintf(opt.log,"%d links added from %s"LF,n,opt.filelist); test_flush;
  667.         }
  668.  
  669.         // Free buffer
  670.         freet(filelist_buff);
  671.       } else {
  672.         if (opt.errlog!=NULL) {
  673.           fspc(opt.errlog,"error"); fprintf(opt.errlog,"Could not include URL list: %s"LF,opt.filelist); test_flush;
  674.         }
  675.       }
  676.     }
  677.  
  678.  
  679.     // lien primaire
  680.     liens_record("primary","/primary",fslash(fconcat(opt.path_html,"index.html")),"","",opt.urlhack);
  681.     if (liens[lien_tot]==NULL) {  // erreur, pas de place rΘservΘe
  682.       printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  683.       if (opt.errlog) {
  684.         fprintf(opt.errlog,"Not enough memory, can not re-allocate %d bytes"LF,(int)((add_tab_alloc+1)*sizeof(lien_url)));
  685.         test_flush;
  686.       }
  687.       XH_extuninit;    // dΘsallocation mΘmoire & buffers
  688.       return 0;
  689.     }    
  690.     liens[lien_tot]->testmode=0;          // pas mode test
  691.     liens[lien_tot]->link_import=0;       // pas mode import
  692.     liens[lien_tot]->depth=opt.depth+1;   // lien de prioritΘ maximale
  693.     liens[lien_tot]->pass2=0;             // 1Φre passe
  694.     liens[lien_tot]->retry=opt.retry;     // lien de prioritΘ maximale
  695.     liens[lien_tot]->premier=lien_tot;    // premier lien, objet-pΦre=objet              
  696.     liens[lien_tot]->precedent=lien_tot;  // lien prΘcΘdent
  697.     lien_tot++;  
  698.  
  699.     // Initialiser cache
  700.     {
  701.       int backupXFR = htsMemoryFastXfr;
  702. #if HTS_ANALYSTE
  703.       _hts_in_html_parsing=4;
  704. #endif
  705.       if (!hts_htmlcheck_loop(NULL,0,0,0,lien_tot,0,NULL)) {
  706.         exit_xh=1;  // exit requested
  707.       }
  708.       htsMemoryFastXfr = 1;               /* fast load */
  709.       cache_init(&cache,&opt);
  710.       htsMemoryFastXfr = backupXFR;
  711. #if HTS_ANALYSTE
  712.       _hts_in_html_parsing=0;
  713. #endif
  714.     }
  715.  
  716.   }
  717.   
  718. #if BDEBUG==3
  719.   {
  720.     int i;
  721.     for(i=0;i<lien_tot;i++) {
  722.       printf("%d>%s%s as %s\n",i,liens[i]->adr,liens[i]->fil,liens[i]->sav);
  723.     }
  724.     for(i=0;i<filptr;i++) {
  725.       printf("%d>filters=%s\n",i,filters[i]);
  726.     }
  727.   }
  728. #endif
  729.    
  730.   // backing
  731.   //soc_max=opt.maxsoc;
  732.   if (opt.maxsoc>0) {
  733. #if BDEBUG==2
  734.     _CLRSCR;
  735. #endif
  736.     // Nombre de fichiers HTML pouvant Ωtre prΘsents en mΘmoire de maniΦre simultannΘe
  737.     // On prΘvoit large: les fichiers HTML ne prennent que peu de place en mΘmoire, et les
  738.     // fichiers non html sont sauvΘs en direct sur disque.
  739.     // --> 1024 entrΘes + 32 entrΘes par socket en supplΘment
  740.     sback = back_new(opt.maxsoc*32+1024);   
  741.     if (sback == NULL) {
  742.       if (opt.errlog)
  743.         fprintf(opt.errlog,"Not enough memory, can not allocate %d bytes"LF,(int)((opt.maxsoc+1)*sizeof(lien_back)));
  744.       return 0;
  745.     }
  746.   }
  747.  
  748.  
  749.   // flush
  750.   test_flush;
  751.  
  752.   // statistiques
  753.   if (opt.makestat) {
  754.     makestat_fp=fopen(fconcat(opt.path_log,"hts-stats.txt"),"wb");
  755.     if (makestat_fp != NULL) {
  756.       fprintf(makestat_fp,"HTTrack statistics report, every minutes"LF LF);
  757.       fflush(makestat_fp);
  758.     }
  759.   }
  760.  
  761.   // tracking -- dΘbuggage
  762.   if (opt.maketrack) {
  763.     maketrack_fp=fopen(fconcat(opt.path_log,"hts-track.txt"),"wb");
  764.     if (maketrack_fp != NULL) {
  765.       fprintf(maketrack_fp,"HTTrack tracking report, every minutes"LF LF);
  766.       fflush(maketrack_fp);
  767.     }
  768.   }
  769.  
  770.   // on n'a pas de liens!! (exemple: httrack www.* impossible sans dΘpart..)
  771.   if (lien_tot<=0) {
  772.     if (opt.errlog) {
  773.       fprintf(opt.errlog,"Error! You MUST specify at least one complete URL, and not only wildcards!"LF);
  774.     }
  775.   }
  776.  
  777.   /* Send options to callback functions */
  778. #if HTS_ANALYSTE
  779.   if (hts_htmlcheck_chopt != NULL) {
  780.     hts_htmlcheck_chopt(&opt);
  781.   }
  782. #endif
  783.  
  784.   // attendre une certaine heure..
  785.   if (opt.waittime>0) {
  786.     int rollover=0;
  787.     int ok=0;
  788.     {
  789.       TStamp tl=0;
  790.       time_t tt;
  791.       struct tm* A;
  792.       tt=time(NULL);
  793.       A=localtime(&tt);
  794.       tl+=A->tm_sec;
  795.       tl+=A->tm_min*60;
  796.       tl+=A->tm_hour*60*60;
  797.       if (tl>opt.waittime)  // attendre minuit
  798.         rollover=1;
  799.     }
  800.  
  801.     // attendre..
  802.     _hts_in_html_parsing=5;
  803.     do {
  804.       TStamp tl=0;
  805.       time_t tt;
  806.       struct tm* A;
  807.       tt=time(NULL);
  808.       A=localtime(&tt);
  809.       tl+=A->tm_sec;
  810.       tl+=A->tm_min*60;
  811.       tl+=A->tm_hour*60*60;
  812.  
  813.       if (rollover) {
  814.         if (tl<=opt.waittime)
  815.           rollover=0;  // attendre heure
  816.       } else {
  817.         if (tl>opt.waittime)
  818.           ok=1;  // ok!
  819.       }
  820.       
  821. #if HTS_ANALYSTE
  822.       if (hts_htmlcheck_loop != NULL) {  
  823.         int r;
  824.         if (rollover)
  825.           r=hts_htmlcheck_loop(sback->lnk, sback->count,0,0,lien_tot,(int) (opt.waittime-tl+24*3600),NULL);
  826.         else
  827.           r=hts_htmlcheck_loop(sback->lnk, sback->count,0,0,lien_tot,(int) (opt.waittime-tl),NULL);
  828.         if (!r) {
  829.           exit_xh=1;  // exit requested
  830.           ok=1;          
  831.         } else
  832.           Sleep(100);
  833.       }
  834. #endif
  835.     } while(!ok);    
  836.     _hts_in_html_parsing=0;
  837.     
  838.     // note: recopie de plus haut
  839.     // noter heure actuelle de dΘpart en secondes
  840.     HTS_STAT.stat_timestart=time_local();
  841.     /*
  842.     if (opt.aff_progress)
  843.       lastime=HTS_STAT.stat_timestart;
  844.       */
  845.     if (opt.shell) {
  846.       last_info_shell=HTS_STAT.stat_timestart;
  847.     }
  848.     if ((opt.makestat) || (opt.maketrack)){
  849.       makestat_time=HTS_STAT.stat_timestart;
  850.     }
  851.  
  852.  
  853.   }  
  854.   /* Info for wrappers */
  855.   if ( (opt.debug>0) && (opt.log!=NULL) ) {
  856.     fspc(opt.log,"info"); fprintf(opt.log,"engine: start"LF);
  857.   }
  858. #if HTS_ANALYSTE
  859.   if (hts_htmlcheck_start != NULL) {
  860.     if (!hts_htmlcheck_start(&opt)) {
  861.       XH_extuninit;
  862.       return 1;
  863.     }
  864.   }
  865.   set_wrappers();   // _start() is allowed to set other wrappers
  866. #endif
  867.   
  868.  
  869.   // ------------------------------------------------------------
  870.  
  871.   // ------------------------------------------------------------
  872.   // Boucle gΘnΘrale de parcours des liens
  873.   // ------------------------------------------------------------
  874.   do {
  875.     int error=0;          // si error alors sauter
  876.     int store_errpage=0;  // c'est une erreur mais on enregistre le html
  877.     char BIGSTK loc[HTS_URLMAXSIZE*2];    // adresse de relocation
  878.  
  879.     // Ici on charge le fichier (html, gif..) en mΘmoire
  880.     // Les HTMLs sont traitΘs (si leur prioritΘ est suffisante)
  881.  
  882.     // effacer r
  883.     memset(&r, 0, sizeof(htsblk)); r.soc=INVALID_SOCKET;
  884.     r.location=loc;    // en cas d'erreur 3xx (moved)
  885.     // recopier proxy
  886.     memcpy(&(r.req.proxy), &opt.proxy, sizeof(opt.proxy));
  887.     // et user-agent
  888.     strcpybuff(r.req.user_agent,opt.user_agent);
  889.     strcpybuff(r.req.referer,opt.referer);
  890.     strcpybuff(r.req.from,opt.from);
  891.     strcpybuff(r.req.lang_iso,opt.lang_iso);
  892.     r.req.user_agent_send=opt.user_agent_send;
  893.  
  894.     if (!error) {
  895.       
  896.       // Skip empty/invalid/done in background
  897.       if (liens[ptr]) {
  898.         while (  (liens[ptr]) && (
  899.                     ( ((urladr != NULL)?(urladr):(" "))[0]=='!') ||
  900.                     ( ((urlfil != NULL)?(urlfil):(" "))[0]=='\0') ||
  901.                     ( (liens[ptr]->pass2 == -1) )
  902.                  )
  903.                ) {  // sauter si lien annulΘ (ou fil vide)
  904.           if ((opt.debug>1) && (opt.log!=NULL)) {
  905.                         if (liens[ptr] != NULL && liens[ptr]->pass2 == -1) {
  906.                 fspc(opt.log,"debug"); fprintf(opt.log,"link #%d is ready, skipping: %s%s.."LF,ptr,((urladr != NULL)?(urladr):(" ")),((urlfil != NULL)?(urlfil):(" ")));
  907.                         } else {
  908.                 fspc(opt.log,"debug"); fprintf(opt.log,"link #%d seems ready, skipping: %s%s.."LF,ptr,((urladr != NULL)?(urladr):(" ")),((urlfil != NULL)?(urlfil):(" ")));
  909.                         }
  910.             test_flush;
  911.           }
  912.           // remove from stats
  913.           if (liens[ptr]->pass2 == -1) {
  914.             HTS_STAT.stat_background--;
  915.           }
  916.           ptr++;
  917.         }
  918.       }
  919.       if (liens[ptr]) {    // on a qq chose α rΘcupΘrer?
  920.  
  921.         if ( (opt.debug>1) && (opt.log!=NULL) ) {
  922.           fspc(opt.log,"debug"); fprintf(opt.log,"Wait get: %s%s"LF,urladr,urlfil);
  923.           test_flush;
  924. #if DEBUG_ROBOTS
  925.           if (strcmp(urlfil,"/robots.txt") == 0) {
  926.             printf("robots.txt detected\n");
  927.           }
  928. #endif
  929.         }    
  930.         // ------------------------------------------------------------
  931.         // DEBUT --RECUPERATION LIEN---
  932.         if (ptr==0) {              // premier lien α parcourir: lien primaire construit avant
  933.           r.adr=primary; primary=NULL;
  934.           r.statuscode=200;
  935.           r.size=strlen(r.adr);
  936.           r.soc=INVALID_SOCKET;
  937.           strcpybuff(r.contenttype,"text/html");
  938.         /*} else if (opt.maxsoc<=0) {   // fichiers 1 α 1 en attente (pas de backing)
  939.           // charger le fichier en mΘmoire tout bΩtement
  940.           r=xhttpget(urladr,urlfil);
  941.           //
  942.         */
  943.         } else {    // backing, multiples sockets
  944.           
  945.           
  946.           /*
  947.             **************************************
  948.             Get the next link, waiting for other files, handling external callbacks
  949.           */
  950.           {
  951.             char BIGSTK buff_err_msg[1024];
  952.             htsmoduleStruct BIGSTK str;
  953.             htsmoduleStructExtended BIGSTK stre;
  954.             buff_err_msg[0] = '\0';
  955.             memset(&str, 0, sizeof(str));
  956.             memset(&stre, 0, sizeof(stre));
  957.             /* */
  958.             str.err_msg = buff_err_msg;
  959.             str.filename = savename;
  960.             str.mime = r.contenttype;
  961.             str.url_host = urladr;
  962.             str.url_file = urlfil;
  963.             str.size = (int) r.size;
  964.             /* */
  965.             str.addLink = htsAddLink;
  966.             /* */
  967.             str.liens = liens;
  968.             str.opt = &opt;
  969.             str.sback = sback;
  970.             str.cache = &cache;
  971.             str.hashptr = hashptr;
  972.             str.numero_passe = numero_passe;
  973.             str.add_tab_alloc = add_tab_alloc;
  974.             /* */
  975.             str.lien_tot_ = &lien_tot;
  976.             str.ptr_ = &ptr;
  977.             str.lien_size_ = &lien_size;
  978.             str.lien_buffer_ = &lien_buffer;
  979.             /* */
  980.             /* */
  981.             stre.r_ = &r;
  982.             /* */
  983.             stre.error_ = &error;
  984.             stre.exit_xh_ = &exit_xh;
  985.             stre.store_errpage_ = &store_errpage;
  986.             /* */
  987.             stre.base = base;
  988.             stre.codebase = codebase;
  989.             /* */
  990.             stre.filters_ = &filters;
  991.             stre.filptr_ = &filptr;
  992.             stre.robots_ = &robots;
  993.             stre.hash_ = &hash;
  994.             stre.lien_max_ = &lien_max;
  995.             /* */
  996.             stre.makeindex_done_ = &makeindex_done;
  997.             stre.makeindex_fp_ = &makeindex_fp;
  998.             stre.makeindex_links_ = &makeindex_links;
  999.             stre.makeindex_firstlink_ = makeindex_firstlink;
  1000.             /* */
  1001.             stre.template_header_ = template_header;
  1002.             stre.template_body_ = template_body;
  1003.             stre.template_footer_ = template_footer;
  1004.             /* */
  1005.             stre.stat_fragment_ = &stat_fragment;
  1006.             stre.makestat_time = makestat_time;
  1007.             stre.makestat_fp = makestat_fp;
  1008.             stre.makestat_total_ = &makestat_total;
  1009.             stre.makestat_lnk_ = &makestat_lnk;
  1010.             stre.maketrack_fp = maketrack_fp;
  1011.             /* FUNCTION DEPENDANT */
  1012.             stre.loc_ = loc;
  1013.             stre.last_info_shell_ = &last_info_shell;
  1014.             stre.info_shell_ = &info_shell;
  1015.  
  1016.             /* Parse */
  1017.             switch(hts_mirror_wait_for_next_file(&str, &stre)) {
  1018.             case -1:
  1019.               XH_uninit;
  1020.               return -1;
  1021.               break;
  1022.             case 2:
  1023.               // Jump to 'continue'
  1024.               // This is one of the very very rare cases where goto
  1025.               // is acceptable
  1026.               // A supplemental flag and if( ) { } would be really messy
  1027.               goto jump_if_done;
  1028.             }
  1029.             
  1030.           }
  1031.           
  1032.           
  1033.         }
  1034.         // FIN --RECUPERATION LIEN--- 
  1035.         // ------------------------------------------------------------
  1036.         
  1037.         
  1038.         
  1039.       } else {    // lien vide..
  1040.         if (opt.errlog && opt.debug > 0) {
  1041.           fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Warning, link #%d empty"LF,ptr); test_flush;
  1042.         }         
  1043.         error=1;
  1044.         goto jump_if_done;
  1045.       }  // test si url existe (non vide!)
  1046.       
  1047.  
  1048.  
  1049.       // ---tester taille a posteriori---
  1050.       // tester r.adr
  1051.       if (!error) {
  1052.         // erreur, pas de fichier chargΘ:
  1053.         if ((!r.adr) && (r.is_write==0) 
  1054.           && (r.statuscode!=301) 
  1055.           && (r.statuscode!=302) 
  1056.           && (r.statuscode!=303) 
  1057.           && (r.statuscode!=307) 
  1058.           && (r.statuscode!=412)
  1059.           && (r.statuscode!=416)
  1060.          ) { 
  1061.           // error=1;
  1062.           
  1063.           // peut Ωtre que le fichier Θtait trop gros?
  1064.           if ((istoobig(r.totalsize,opt.maxfile_html,opt.maxfile_nonhtml,r.contenttype))
  1065.            || (istoobig(r.totalsize,opt.maxfile_html,opt.maxfile_nonhtml,r.contenttype))) {
  1066.             error=0;
  1067.             if (opt.errlog) {
  1068.               fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Big file cancelled according to user's preferences: %s%s"LF,urladr,urlfil);
  1069.               test_flush;
  1070.             }
  1071.           }
  1072.           // // // error=1;    // ne pas traiter la suite -- euhh si finalement..
  1073.         }
  1074.       }
  1075.       // ---fin tester taille a posteriori---    
  1076.  
  1077.       
  1078.       // -------------------- 
  1079.       // BOGUS MIME TYPE HACK
  1080.       // Check if we have a bogus MIME type
  1081.       // example: 
  1082.       // Content-type="text/html"
  1083.       // and 
  1084.       // Content-disposition="foo.jpg"
  1085.       // --------------------
  1086.       if (!error) {
  1087.         if (r.statuscode == 200) {    // OK (ou 304 en backing)
  1088.           if (r.adr) {    // Written file
  1089.             if ( (is_hypertext_mime(r.contenttype, urlfil))   /* Is HTML or Js, .. */
  1090.                             /* NO - real media is real media, and mms is mms, not HTML */
  1091.               /*|| (may_be_hypertext_mime(r.contenttype, urlfil) && (r.adr) )*/  /* Is real media, .. */
  1092.               ) {
  1093.               if (strnotempty(r.cdispo)) {      // Content-disposition set!
  1094.                 if (ishtml(savename) == 0) {    // Non HTML!!
  1095.                   // patch it!
  1096.                   strcpybuff(r.contenttype,"application/octet-stream");
  1097.                 }
  1098.               }
  1099.             }
  1100.           }
  1101.         }
  1102.         
  1103.         // ------------------------------------
  1104.         // BOGUS MIME TYPE HACK II (the revenge)
  1105.         // Check if we have a bogus MIME type
  1106.         if ( (is_hypertext_mime(r.contenttype, urlfil))   /* Is HTML or Js, .. */
  1107.           || (may_be_hypertext_mime(r.contenttype, urlfil))  /* Is real media, .. */
  1108.           ) {
  1109.           if ((r.adr) && (r.size)) {
  1110.             unsigned int map[256];
  1111.             int i;
  1112.             unsigned int nspec = 0;
  1113.             map_characters((unsigned char*)r.adr, (unsigned int)r.size, (unsigned int*)map);
  1114.             for(i = 1 ; i < 32 ; i++) {   //  null chars ignored..
  1115.               if (!is_realspace(i) 
  1116.                 && i != 27        /* Damn you ISO2022-xx! */
  1117.                 ) {
  1118.                 nspec += map[i];
  1119.               }
  1120.             }
  1121.             /* On-the-fly UCS2 to UTF-8 conversion (note: UCS2 should never be used on the net) */
  1122.             if (
  1123.               map[0] > r.size/10
  1124.               &&
  1125.               r.size % 2 == 0
  1126.               &&
  1127.               (
  1128.               ( ((unsigned char) r.adr[0]) == 0xff && ((unsigned char) r.adr[1]) == 0xfe)
  1129.                             ||
  1130.                             ( ((unsigned char) r.adr[0]) == 0xfe && ((unsigned char) r.adr[1]) == 0xff)
  1131.                             )
  1132.                             ) 
  1133.                         {
  1134. #define CH_ADD(c) do {                                                            \
  1135.     if (new_offs + 1 > new_capa) {                                        \
  1136.         new_capa *= 2;                                                                    \
  1137.         new_adr = (unsigned char*) realloct(new_adr,    \
  1138.                                             new_capa);     \
  1139.         assertf(new_adr != NULL);                                                \
  1140.     }                                                                                                    \
  1141.     new_adr[new_offs++] = (unsigned char) (c);        \
  1142. } while(0)
  1143. #define CH_ADD_RNG1(c, r, o) do {                   \
  1144.     CH_ADD( (c) / (r) + (o) );                        \
  1145.     c = (c) % (r);                                    \
  1146. } while(0)
  1147. #define CH_ADD_RNG0(c, o) do {                      \
  1148.     CH_ADD_RNG1(c, 1, o);                                                          \
  1149. } while(0)
  1150. #define CH_ADD_RNG2(c, r, r2, o) do {               \
  1151.     CH_ADD_RNG1(c, (r) * (r2), o);                                         \
  1152. } while(0)
  1153.                             int new_capa = r.size / 2 + 1;
  1154.                             int new_offs = 0;
  1155.                             unsigned char* prev_adr = (unsigned char*) r.adr;
  1156.                             unsigned char* new_adr = (unsigned char*) malloct(new_capa);
  1157.                             int i;
  1158.                             int swap = (((unsigned char)r.adr[0]) == 0xff);
  1159.                             assertf(new_adr != NULL);
  1160.                             /* 
  1161.                             See http://www.unicode.org/reports/tr28/tr28-3.html#conformance 
  1162.                             U+0000..U+007F 00..7F       
  1163.                             U+0080..U+07FF C2..DF  80..BF      
  1164.                             U+0800..U+0FFF E0      A0..BF  80..BF    
  1165.                             U+1000..U+CFFF E1..EC  80..BF  80..BF    
  1166.                             U+D000..U+D7FF ED      80..9F  80..BF    
  1167.                             U+D800..U+DFFF
  1168.                             U+E000..U+FFFF EE..EF  80..BF  80..BF    
  1169.                             */
  1170.                             for(i = 0 ; i < r.size / 2 ; i++) {
  1171.                                 unsigned short int unic = 0;
  1172.                                 if (swap)
  1173.                                     unic = prev_adr[i*2] + (prev_adr[i*2 + 1] << 8);
  1174.                                 else
  1175.                                     unic = (prev_adr[i*2] << 8) + prev_adr[i*2 + 1];
  1176.                                 if (unic <= 0x7F) {
  1177.                                     /* U+0000..U+007F 00..7F      */
  1178.                                     CH_ADD_RNG0( unic,               0x00 );
  1179.                                 } else if (unic <= 0x07FF) {
  1180.                                     /* U+0080..U+07FF C2..DF  80..BF */
  1181.                                     unic -= 0x0080;
  1182.                                     CH_ADD_RNG1( unic, 0xbf - 0x80 + 1, 0xc2 );
  1183.                                     CH_ADD_RNG0( unic,                  0x80 );
  1184.                                 } else if (unic <= 0x0FFF) {
  1185.                                     /* U+0800..U+0FFF E0      A0..BF  80..BF */
  1186.                                     unic -= 0x0800;
  1187.                                     CH_ADD_RNG2( unic, 0xbf - 0x80 + 1, 0xbf - 0xa0 + 1, 0xe0 );
  1188.                                     CH_ADD_RNG1( unic, 0xbf - 0x80 + 1, 0xa0 );
  1189.                                     CH_ADD_RNG0( unic,                  0x80 );
  1190.                                 } else if (unic <= 0xCFFF) {
  1191.                                     /* U+1000..U+CFFF E1..EC  80..BF  80..BF */
  1192.                                     unic -= 0x1000;
  1193.                                     CH_ADD_RNG2( unic, 0xbf - 0x80 + 1, 0xbf - 0x80 + 1, 0xe1 );
  1194.                                     CH_ADD_RNG1( unic, 0xbf - 0x80 + 1, 0x80 );
  1195.                                     CH_ADD_RNG0( unic,                  0x80 );
  1196.                                 } else if (unic <= 0xD7FF) {
  1197.                                     /* U+D000..U+D7FF ED      80..9F  80..BF */
  1198.                                     unic -= 0xD000;
  1199.                                     CH_ADD_RNG2( unic, 0xbf - 0x80 + 1, 0x9f - 0x80 + 1, 0xed );
  1200.                                     CH_ADD_RNG1( unic, 0xbf - 0x80 + 1, 0x80 );
  1201.                                     CH_ADD_RNG0( unic,                  0x80 );
  1202.                                 } else if (unic <= 0xDFFF) {
  1203.                                     /* U+D800..U+DFFF */
  1204.                                     CH_ADD('?');
  1205.                                     /* ill-formed */
  1206.                                 } else if (unic <= 0xFFFF) {
  1207.                                     /* U+E000..U+FFFF EE..EF  80..BF  80..BF */
  1208.                                     unic -= 0xE000;
  1209.                                     CH_ADD_RNG2( unic, 0xbf - 0x80 + 1, 0xbf - 0x80 + 1, 0xee );
  1210.                                     CH_ADD_RNG1( unic, 0xbf - 0x80 + 1, 0x80 );
  1211.                                     CH_ADD_RNG0( unic,                  0x80 );
  1212.                                 }
  1213.                             }
  1214.                             if (opt.errlog) {
  1215.                                 fspc(opt.errlog,"warning"); fprintf(opt.errlog,"File %s%s converted from UCS2 to UTF-8 (old size: %d bytes, new size: %d bytes)"LF, urladr, urlfil, (int)r.size, new_offs);
  1216.                                 test_flush;
  1217.                             }
  1218.                             freet(r.adr);
  1219.                             r.adr = NULL;
  1220.                             r.size = new_offs;
  1221.                             CH_ADD(0);
  1222.                             r.adr = (char*) new_adr;
  1223. #undef CH_ADD
  1224. #undef CH_ADD_RNG0
  1225. #undef CH_ADD_RNG1
  1226. #undef CH_ADD_RNG2
  1227.                         } else if ((nspec > r.size / 100) && (nspec > 10)) {    // too many special characters
  1228.                             strcpybuff(r.contenttype,"application/octet-stream");
  1229.                             if (opt.errlog) {
  1230.                                 fspc(opt.errlog,"warning"); fprintf(opt.errlog,"File not parsed, looks like binary: %s%s"LF,urladr,urlfil);
  1231.                                 test_flush;
  1232.                             }
  1233.                         }
  1234.  
  1235.                         /* This hack allows to avoid problems with parsing '\0' characters  */
  1236.                         for(i = 0 ; i < r.size ; i++) {
  1237.                             if (r.adr[i] == '\0') r.adr[i] = ' ';
  1238.                         }
  1239.  
  1240.           }
  1241.  
  1242.  
  1243.         }
  1244.       }
  1245.       
  1246.             // MOVED IN back_finalize()
  1247.             //
  1248.       // -------------------- 
  1249.       // REAL MEDIA HACK
  1250.       // Check if we have to load locally the file
  1251.       // --------------------
  1252.       //if (!error) {
  1253.       //  if (r.statuscode == 200) {    // OK (ou 304 en backing)
  1254.       //    if (r.adr==NULL) {    // Written file
  1255.       //      if (may_be_hypertext_mime(r.contenttype, urlfil)) {   // to parse!
  1256.       //        LLint sz;
  1257.       //        sz=fsize(savename);
  1258.       //        if (sz>0) {   // ok, exists!
  1259.       //          if (sz < 8192) {   // ok, small file --> to parse!
  1260.       //            FILE* fp=fopen(savename,"rb");
  1261.       //            if (fp) {
  1262.       //              r.adr=malloct((int)sz + 2);
  1263.       //              if (r.adr) {
  1264.       //                if (fread(r.adr,1,(INTsys)sz,fp) == sz) {
  1265.       //                  r.size=sz;
  1266.       //                        r.adr[sz] = '\0';
  1267.       //                        r.is_write = 0;
  1268.       //                } else {
  1269.       //                  freet(r.adr);
  1270.       //                  r.size=0;
  1271.       //                  r.adr = NULL;
  1272.       //                  r.statuscode=STATUSCODE_INVALID;
  1273.       //                  strcpybuff(r.msg, ".RAM read error");
  1274.       //                }
  1275.       //                fclose(fp);
  1276.       //                fp=NULL;
  1277.       //                // remove (temporary) file!
  1278.       //                remove(savename);
  1279.       //              }
  1280.       //              if (fp)
  1281.       //                fclose(fp);
  1282.       //            }
  1283.       //          }
  1284.       //        }
  1285.       //      }
  1286.       //    }
  1287.       //  }
  1288.       //}
  1289.       // EN OF REAL MEDIA HACK
  1290.       
  1291.  
  1292.       // ---stockage en cache---
  1293.       // stocker dans le cache?
  1294.       /*
  1295.       if (!error) {
  1296.         if (ptr>0) {
  1297.           if (liens[ptr]) {
  1298.             xxcache_mayadd(&opt,&cache,&r,urladr,urlfil,savename);
  1299.           } else
  1300.             error=1;
  1301.         }
  1302.       }
  1303.       */
  1304.       // ---fin stockage en cache---
  1305.       
  1306.       
  1307.       
  1308.       /*
  1309.          **************************************
  1310.          Check "Moved permanently" and other similar errors, retrying URLs if necessary and handling
  1311.          redirect pages.
  1312.       */
  1313.       if (!error) {
  1314.         char BIGSTK buff_err_msg[1024];
  1315.         htsmoduleStruct BIGSTK str;
  1316.         htsmoduleStructExtended BIGSTK stre;
  1317.         buff_err_msg[0] = '\0';
  1318.         memset(&str, 0, sizeof(str));
  1319.         memset(&stre, 0, sizeof(stre));
  1320.         /* */
  1321.         str.err_msg = buff_err_msg;
  1322.         str.filename = savename;
  1323.         str.mime = r.contenttype;
  1324.         str.url_host = urladr;
  1325.         str.url_file = urlfil;
  1326.         str.size = (int) r.size;
  1327.         /* */
  1328.         str.addLink = htsAddLink;
  1329.         /* */
  1330.         str.liens = liens;
  1331.         str.opt = &opt;
  1332.         str.sback = sback;
  1333.         str.cache = &cache;
  1334.         str.hashptr = hashptr;
  1335.         str.numero_passe = numero_passe;
  1336.         str.add_tab_alloc = add_tab_alloc;
  1337.         /* */
  1338.         str.lien_tot_ = &lien_tot;
  1339.         str.ptr_ = &ptr;
  1340.         str.lien_size_ = &lien_size;
  1341.         str.lien_buffer_ = &lien_buffer;
  1342.         /* */
  1343.         /* */
  1344.         stre.r_ = &r;
  1345.         /* */
  1346.         stre.error_ = &error;
  1347.         stre.exit_xh_ = &exit_xh;
  1348.         stre.store_errpage_ = &store_errpage;
  1349.         /* */
  1350.         stre.base = base;
  1351.         stre.codebase = codebase;
  1352.         /* */
  1353.         stre.filters_ = &filters;
  1354.         stre.filptr_ = &filptr;
  1355.         stre.robots_ = &robots;
  1356.         stre.hash_ = &hash;
  1357.         stre.lien_max_ = &lien_max;
  1358.         /* */
  1359.         stre.makeindex_done_ = &makeindex_done;
  1360.         stre.makeindex_fp_ = &makeindex_fp;
  1361.         stre.makeindex_links_ = &makeindex_links;
  1362.         stre.makeindex_firstlink_ = makeindex_firstlink;
  1363.         /* */
  1364.         stre.template_header_ = template_header;
  1365.         stre.template_body_ = template_body;
  1366.         stre.template_footer_ = template_footer;
  1367.         /* */
  1368.         stre.stat_fragment_ = &stat_fragment;
  1369.         stre.makestat_time = makestat_time;
  1370.         stre.makestat_fp = makestat_fp;
  1371.         stre.makestat_total_ = &makestat_total;
  1372.         stre.makestat_lnk_ = &makestat_lnk;
  1373.         stre.maketrack_fp = maketrack_fp;
  1374.         
  1375.         /* Parse */
  1376.         if (hts_mirror_check_moved(&str, &stre) != 0) {
  1377.           XH_uninit;
  1378.           return -1;
  1379.         }
  1380.         
  1381.       }
  1382.  
  1383.     }  // if !error
  1384.     
  1385.     if (!error) {
  1386. #if DEBUG_SHOWTYPES
  1387.       if (strstr(REG,r.contenttype)==NULL) {
  1388.         strcatbuff(REG,r.contenttype);
  1389.         strcatbuff(REG,"\n");
  1390.         printf("%s\n",r.contenttype);
  1391.         io_flush;
  1392.       }
  1393. #endif
  1394.       
  1395.       /* Load file if necessary */
  1396.       if ( 
  1397.         is_hypertext_mime(r.contenttype, urlfil)   /* Is HTML or Js, .. */
  1398.         && (liens[ptr]->depth>0)            /* Depth > 0 (recurse depth) */
  1399.         && (r.adr==NULL)        /* HTML Data exists */
  1400.         && (!store_errpage)     /* Not an html error page */
  1401.         && (savename[0]!='\0')  /* Output filename exists */
  1402.         ) 
  1403.       {
  1404.         r.adr = readfile2(savename, &r.size);
  1405.         (void) unlink(fconv(savename));
  1406.         if (r.adr != NULL) {
  1407.           if ( (opt.debug>0) && (opt.log!=NULL) ) {
  1408.             fspc(opt.log,"info"); fprintf(opt.log,"File successfully loaded for parsing: %s%s (%d bytes)"LF,urladr,urlfil,(int)r.size);
  1409.             test_flush;
  1410.           }
  1411.         } else {
  1412.           if ( opt.log != NULL ) {
  1413.             fspc(opt.log,"error"); fprintf(opt.log,"File could not be loaded for parsing: %s%s"LF,urladr,urlfil);
  1414.             test_flush;
  1415.           }
  1416.         }
  1417.       }
  1418.  
  1419.       // ------------------------------------------------------
  1420.       // ok, fichier chargΘ localement
  1421.       // ------------------------------------------------------
  1422.       
  1423.       // VΘrificateur d'intΘgritΘ
  1424.       #if DEBUG_CHECKINT
  1425.       {
  1426.         int i;
  1427.         for(i = 0 ; i < sback->count ; i++) {
  1428.           char si[256];
  1429.           sprintf(si,"Test global aprΦs back_wait, index %d",i);
  1430.           _CHECKINT(&back[i],si)
  1431.         }
  1432.       }
  1433.       #endif
  1434.  
  1435.  
  1436.       /* info: updated */
  1437.       /*
  1438.       if (ptr>0) {
  1439.         // "mis α jour"
  1440.         if ((!r.notmodified) && (opt.is_update) && (!store_errpage)) {    // page modifiΘe
  1441.           if (strnotempty(savename)) {
  1442.             HTS_STAT.stat_updated_files++;
  1443.             if (opt.log!=NULL) {
  1444.               //if ((opt.debug>0) && (opt.log!=NULL)) {
  1445.               fspc(opt.log,"info"); fprintf(opt.log,"File updated: %s%s"LF,urladr,urlfil);
  1446.               test_flush;
  1447.             }
  1448.           }
  1449.         } else {
  1450.           if (!store_errpage) {
  1451.             if ( (opt.debug>0) && (opt.log!=NULL) ) {
  1452.               fspc(opt.log,"info"); fprintf(opt.log,"File recorded: %s%s"LF,urladr,urlfil);
  1453.               test_flush;
  1454.             }
  1455.           }
  1456.         }
  1457.       }
  1458.       */
  1459.       
  1460.       // ------------------------------------------------------
  1461.       // traitement (parsing)
  1462.       // ------------------------------------------------------
  1463.  
  1464.       // traiter
  1465.       if (
  1466.            ( (is_hypertext_mime(r.contenttype, urlfil))   /* Is HTML or Js, .. */
  1467.              || (may_be_hypertext_mime(r.contenttype, urlfil) && r.adr != NULL )  /* Is real media, .. */
  1468.            )
  1469.         && (liens[ptr]->depth>0)            /* Depth > 0 (recurse depth) */
  1470.         && (r.adr!=NULL)        /* HTML Data exists */
  1471.         && (r.size>0)           /* And not empty */
  1472.         && (!store_errpage)     /* Not an html error page */
  1473.         && (savename[0]!='\0')  /* Output filename exists */
  1474.         ) {    // ne traiter que le html si autorisΘ
  1475.         // -- -- -- --
  1476.         // Parsing HTML
  1477.         if (!error) {
  1478.           /* Info for wrappers */
  1479.           if ( (opt.debug>0) && (opt.log!=NULL) ) {
  1480.             fspc(opt.log,"info"); fprintf(opt.log,"engine: check-html: %s%s"LF,urladr,urlfil);
  1481.           }
  1482.           {
  1483.             char BIGSTK buff_err_msg[1024];
  1484.             htsmoduleStruct BIGSTK str;
  1485.             htsmoduleStructExtended BIGSTK stre;
  1486.             buff_err_msg[0] = '\0';
  1487.             memset(&str, 0, sizeof(str));
  1488.             memset(&stre, 0, sizeof(stre));
  1489.             /* */
  1490.             str.err_msg = buff_err_msg;
  1491.             str.filename = savename;
  1492.             str.mime = r.contenttype;
  1493.             str.url_host = urladr;
  1494.             str.url_file = urlfil;
  1495.             str.size = (int) r.size;
  1496.             /* */
  1497.             str.addLink = htsAddLink;
  1498.             /* */
  1499.             str.liens = liens;
  1500.             str.opt = &opt;
  1501.             str.sback = sback;
  1502.             str.cache = &cache;
  1503.             str.hashptr = hashptr;
  1504.             str.numero_passe = numero_passe;
  1505.             str.add_tab_alloc = add_tab_alloc;
  1506.             /* */
  1507.             str.lien_tot_ = &lien_tot;
  1508.             str.ptr_ = &ptr;
  1509.             str.lien_size_ = &lien_size;
  1510.             str.lien_buffer_ = &lien_buffer;
  1511.             /* */
  1512.             /* */
  1513.             stre.r_ = &r;
  1514.             /* */
  1515.             stre.error_ = &error;
  1516.             stre.exit_xh_ = &exit_xh;
  1517.             stre.store_errpage_ = &store_errpage;
  1518.             /* */
  1519.             stre.base = base;
  1520.             stre.codebase = codebase;
  1521.             /* */
  1522.             stre.filters_ = &filters;
  1523.             stre.filptr_ = &filptr;
  1524.             stre.robots_ = &robots;
  1525.             stre.hash_ = &hash;
  1526.             stre.lien_max_ = &lien_max;
  1527.             /* */
  1528.             stre.makeindex_done_ = &makeindex_done;
  1529.             stre.makeindex_fp_ = &makeindex_fp;
  1530.             stre.makeindex_links_ = &makeindex_links;
  1531.             stre.makeindex_firstlink_ = makeindex_firstlink;
  1532.             /* */
  1533.             stre.template_header_ = template_header;
  1534.             stre.template_body_ = template_body;
  1535.             stre.template_footer_ = template_footer;
  1536.             /* */
  1537.             stre.stat_fragment_ = &stat_fragment;
  1538.             stre.makestat_time = makestat_time;
  1539.             stre.makestat_fp = makestat_fp;
  1540.             stre.makestat_total_ = &makestat_total;
  1541.             stre.makestat_lnk_ = &makestat_lnk;
  1542.             stre.maketrack_fp = maketrack_fp;
  1543.             
  1544.             /* Parse */
  1545.             if (htsparse(&str, &stre) != 0) {
  1546.               XH_uninit;
  1547.               return -1;
  1548.             }
  1549.  
  1550.  
  1551.           // I'll have to segment this part
  1552. // #include "htsparse.c"
  1553.  
  1554.  
  1555.           }
  1556.         }
  1557.         // Fin parsing HTML
  1558.         // -- -- -- --
  1559.  
  1560.  
  1561.       }  // si text/html
  1562.       // -- -- --
  1563.       else {    // sauver fichier quelconque
  1564.         // -- -- --
  1565.         // sauver fichier
  1566.  
  1567.  
  1568.         /* En cas d'erreur, vΘrifier que fichier d'erreur existe */
  1569.         if (strnotempty(savename) == 0) {           // chemin de sauvegarde existant
  1570.           if (strcmp(urlfil,"/robots.txt")==0) {    // pas robots.txt
  1571.             if (store_errpage) {                    // c'est une page d'erreur
  1572.               int create_html_warning=0;
  1573.               int create_gif_warning=0;
  1574.               switch (ishtml(urlfil)) {      /* pas fichier html */
  1575.               case 0:                        /* non html */
  1576.                 {
  1577.                   char buff[256];
  1578.                   guess_httptype(buff,urlfil);
  1579.                   if (strcmp(buff,"image/gif")==0)
  1580.                     create_gif_warning=1;
  1581.                 }
  1582.                 break;
  1583.               case 1:                        /* html */
  1584.                 if (!r.adr) {
  1585.                 }
  1586.                 break;
  1587.               default:                       /* don't know.. */
  1588.                 break;    
  1589.               }
  1590.               /* CrΘer message d'erreur ? */
  1591.               if (create_html_warning) {
  1592.                 char* adr=(char*)malloct(strlen(HTS_DATA_ERROR_HTML)+1100);
  1593.                 if ( (opt.debug>0) && (opt.log!=NULL) ) {
  1594.                   fspc(opt.log,"info"); fprintf(opt.log,"Creating HTML warning file (%s)"LF,r.msg);
  1595.                   test_flush;
  1596.                 }
  1597.                 if (adr) {
  1598.                   if (r.adr) {
  1599.                     freet(r.adr);
  1600.                     r.adr=NULL;
  1601.                   }
  1602.                   sprintf(adr,HTS_DATA_ERROR_HTML,r.msg);
  1603.                   r.adr=adr;
  1604.                 }
  1605.               } else if (create_gif_warning) {
  1606.                 char* adr=(char*)malloct(HTS_DATA_UNKNOWN_GIF_LEN);
  1607.                 if ( (opt.debug>0) && (opt.log!=NULL) ) {
  1608.                   fspc(opt.log,"info"); fprintf(opt.log,"Creating GIF dummy file (%s)"LF,r.msg);
  1609.                   test_flush;
  1610.                 }
  1611.                 if (r.adr) {
  1612.                   freet(r.adr);
  1613.                   r.adr=NULL;
  1614.                 }
  1615.                 memcpy(adr, HTS_DATA_UNKNOWN_GIF, HTS_DATA_UNKNOWN_GIF_LEN);
  1616.                 r.adr=adr;
  1617.               }
  1618.             }
  1619.           }
  1620.         }
  1621.  
  1622.         if (strnotempty(savename) == 0) {    // pas de chemin de sauvegarde
  1623.           if (strcmp(urlfil,"/robots.txt")==0) {    // robots.txt
  1624.             if (r.adr) {
  1625.               int bptr=0;
  1626.               char BIGSTK line[1024];
  1627.               char BIGSTK buff[8192];
  1628.               char BIGSTK infobuff[8192];
  1629.               int record=0;
  1630.               line[0]='\0'; buff[0]='\0'; infobuff[0]='\0';
  1631.               //
  1632. #if DEBUG_ROBOTS
  1633.               printf("robots.txt dump:\n%s\n",r.adr);
  1634. #endif
  1635.               do {
  1636.                 char* comm;
  1637.                 int llen;
  1638.                 bptr+=binput(r.adr+bptr, line, sizeof(line) - 2);
  1639.                 /* strip comment */
  1640.                 comm=strchr(line, '#');
  1641.                 if (comm != NULL) {
  1642.                   *comm = '\0';
  1643.                 }
  1644.                 /* strip spaces */
  1645.                 llen=strlen(line);
  1646.                 while(llen > 0 && is_realspace(line[llen - 1])) {
  1647.                   line[llen - 1] = '\0';
  1648.                   llen--;
  1649.                 }
  1650.                 if (strfield(line,"user-agent:")) {
  1651.                   char* a;
  1652.                   a=line+11;
  1653.                   while(is_realspace(*a)) a++;    // sauter espace(s)
  1654.                   if ( *a == '*') {
  1655.                     if (record != 2)
  1656.                       record=1;    // c pour nous
  1657.                   } else if (strfield(a,"httrack") || strfield(a,"winhttrack") || strfield(a,"webhttrack")) {
  1658.                     buff[0]='\0';      // re-enregistrer
  1659.                     infobuff[0]='\0';
  1660.                     record=2;          // locked
  1661. #if DEBUG_ROBOTS
  1662.                     printf("explicit disallow for httrack\n");
  1663. #endif
  1664.                   }
  1665.                   else record=0;
  1666.                 } else if (record) {
  1667.                   if (strfield(line,"disallow:")) {
  1668.                     char* a=line+9;
  1669.                     while(is_realspace(*a))
  1670.                       a++;    // sauter espace(s)
  1671.                     if (strnotempty(a)) {
  1672. #ifdef IGNORE_RESTRICTIVE_ROBOTS 
  1673.                       if (strcmp(a,"/") != 0 || opt.robots >= 3) 
  1674. #endif
  1675.                       {      /* ignoring disallow: / */
  1676.                         if ( (strlen(buff) + strlen(a) + 8) < sizeof(buff)) {
  1677.                           strcatbuff(buff,a);
  1678.                           strcatbuff(buff,"\n");
  1679.                           if ( (strlen(infobuff) + strlen(a) + 8) < sizeof(infobuff)) {
  1680.                             if (strnotempty(infobuff)) strcatbuff(infobuff,", ");
  1681.                             strcatbuff(infobuff,a);
  1682.                           }
  1683.                         }
  1684.                       }
  1685. #ifdef IGNORE_RESTRICTIVE_ROBOTS 
  1686.                       else {
  1687.                         if (opt.errlog!=NULL) {
  1688.                           fspc(opt.errlog,"info"); fprintf(opt.errlog,"Note: %s robots.txt rules are too restrictive, ignoring /"LF,urladr);
  1689.                           test_flush;
  1690.                         }
  1691.                       }
  1692. #endif
  1693.                     }
  1694.                   }
  1695.                 }
  1696.               } while( (bptr<r.size) && (strlen(buff) < (sizeof(buff) - 32) ) );
  1697.               if (strnotempty(buff)) {
  1698.                 checkrobots_set(&robots,urladr,buff);
  1699.                 if (opt.log!=NULL) {
  1700.                   if (opt.log != opt.errlog) {
  1701.                     fspc(opt.log,"info"); fprintf(opt.log,"Note: robots.txt forbidden links for %s are: %s"LF,urladr,infobuff);
  1702.                     test_flush;
  1703.                   } 
  1704.                 }
  1705.                 if (opt.errlog!=NULL) {
  1706.                   fspc(opt.errlog,"info"); fprintf(opt.errlog,"Note: due to %s remote robots.txt rules, links begining with these path will be forbidden: %s (see in the options to disable this)"LF,urladr,infobuff);
  1707.                   test_flush;
  1708.                 }
  1709.               }
  1710.             }
  1711.           }
  1712.         } else if (r.is_write) {    // dΘja sauvΘ sur disque
  1713.           /*
  1714.           if (!ishttperror(r.statuscode))
  1715.             HTS_STAT.stat_files++;
  1716.           HTS_STAT.stat_bytes+=r.size;
  1717.           */
  1718.           //printf("ok......\n");
  1719.         } else {
  1720.           // Si on doit sauver une page HTML sans la scanner, cela signifie que le niveau de
  1721.           // rΘcursion nous en empΩche
  1722.           // Dans ce cas on met un fichier indiquant ce fait
  1723.           // Si par la suite on doit retraiter ce fichier avec un niveau de rΘcursion plus
  1724.           // fort, on supprimera le readme, et on scannera le fichier html!
  1725.           // note: sautΘ si store_errpage (cαd si page d'erreur, non α scanner!)
  1726.           if ( (is_hypertext_mime(r.contenttype, urlfil)) && (!store_errpage) && (r.size>0)) {  // c'est du html!!
  1727.             char BIGSTK tempo[HTS_URLMAXSIZE*2];
  1728.             FILE* fp;
  1729.             tempo[0]='\0';
  1730.             strcpybuff(tempo,savename);
  1731.             strcatbuff(tempo,".readme");
  1732.             
  1733. #if HTS_DOSNAME
  1734.             // remplacer / par des slash arriΦre
  1735.             {
  1736.               int i=0;
  1737.               while(tempo[i]) {
  1738.                 if (tempo[i]=='/')
  1739.                   tempo[i]='\\';
  1740.                 i++;
  1741.               } 
  1742.             } 
  1743.             // a partir d'ici le slash devient antislash
  1744. #endif
  1745.             
  1746.             if ((fp=fopen(tempo,"wb"))!=NULL) {
  1747.               fprintf(fp,"Info-file generated by HTTrack Website Copier "HTTRACK_VERSION"%s"CRLF""CRLF, WHAT_is_available);
  1748.               fprintf(fp,"The file %s has not been scanned by HTS"CRLF,savename);
  1749.               fprintf(fp,"Some links contained in it may be unreachable locally."CRLF);
  1750.               fprintf(fp,"If you want to get these files, you have to set an upper recurse level, ");
  1751.               fprintf(fp,"and to rescan the URL."CRLF);
  1752.               fclose(fp);
  1753. #if HTS_WIN==0
  1754.               chmod(tempo,HTS_ACCESS_FILE);      
  1755. #endif
  1756.               usercommand(&opt,0,NULL,fconv(tempo),"","");
  1757.             }
  1758.             
  1759.             
  1760.             if ( (opt.debug>0) && (opt.errlog!=NULL) ) {
  1761.               fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Warning: store %s without scan: %s"LF,r.contenttype,savename);
  1762.               test_flush;
  1763.             }
  1764.           } else {
  1765.             if ((opt.getmode & 2)!=0) {    // ok autorisΘ
  1766.               if ( (opt.debug>1) && (opt.log!=NULL) ) {
  1767.                 fspc(opt.log,"debug"); fprintf(opt.log,"Store %s: %s"LF,r.contenttype,savename);
  1768.                 test_flush;
  1769.               }
  1770.             } else {    // lien non autorisΘ! (ex: cgi-bin en html)
  1771.               if ((opt.debug>1) && (opt.log!=NULL)) {
  1772.                 fspc(opt.log,"debug"); fprintf(opt.log,"non-html file ignored after upload at %s : %s"LF,urladr,urlfil);
  1773.                 test_flush;
  1774.               } 
  1775.               if (r.adr) {
  1776.                 freet(r.adr); r.adr=NULL;
  1777.               }
  1778.             }
  1779.           }
  1780.           
  1781.           //printf("extern=%s\n",r.contenttype);
  1782.  
  1783.           // ATTENTION C'EST ICI QU'ON SAUVE LE FICHIER!!          
  1784.           if (r.adr) {
  1785.             file_notify(urladr,urlfil, savename, 1, 1, r.notmodified);
  1786.             if (filesave(&opt,r.adr,(int)r.size,savename,urladr,urlfil)!=0) {
  1787.               int fcheck;
  1788.               if ((fcheck=check_fatal_io_errno())) {
  1789.                                 fspc(opt.log,"error"); fprintf(opt.log,"Mirror aborted: disk full or filesystem problems"LF); test_flush;
  1790.                 exit_xh=-1;   /* fatal error */
  1791.               }
  1792.               if (opt.errlog) {   
  1793.                 fspc(opt.errlog,"error"); fprintf(opt.errlog,"Unable to save file %s : %s"LF, savename, strerror(errno));
  1794.                 if (fcheck) {
  1795.                   fspc(opt.errlog,"error");
  1796.                   fprintf(opt.errlog,"* * Fatal write error, giving up"LF);
  1797.                 }
  1798.                 test_flush;
  1799.               }
  1800.             } else {
  1801.               /*
  1802.               if (!ishttperror(r.statuscode))
  1803.                 HTS_STAT.stat_files++;
  1804.               HTS_STAT.stat_bytes+=r.size;
  1805.               */
  1806.             }
  1807.           }
  1808.           
  1809.         }
  1810.   
  1811.  
  1812.         /* Parsing of other media types (java, ram..) */
  1813.         /*
  1814.         if (strfield2(r.contenttype,"audio/x-pn-realaudio")) {
  1815.           if ((opt.debug>1) && (opt.log!=NULL)) {
  1816.             fspc(opt.log,"debug"); fprintf(opt.log,"(Real Media): parsing %s"LF,savename); test_flush;
  1817.           }
  1818.           if (fexist(savename)) {   // ok, existe bien!
  1819.             FILE* fp=fopen(savename,"r+b");
  1820.             if (fp) {
  1821.               if (!fseek(fp,0,SEEK_SET)) {
  1822.                 char BIGSTK line[HTS_URLMAXSIZE*2];
  1823.                 linput(fp,line,HTS_URLMAXSIZE);
  1824.                 if (strnotempty(line)) {
  1825.                   if ((opt.debug>1) && (opt.log!=NULL)) {
  1826.                     fspc(opt.log,"debug"); fprintf(opt.log,"(Real Media): detected %s"LF,line); test_flush;
  1827.                   }
  1828.                 }
  1829.               }
  1830.               fclose(fp);
  1831.             }
  1832.           }
  1833.         } else */
  1834.  
  1835.  
  1836.         /* External modules */
  1837.         if (opt.parsejava && fexist(savename)) {
  1838.           char BIGSTK buff_err_msg[1024];
  1839.           htsmoduleStruct BIGSTK str;
  1840.           buff_err_msg[0] = '\0';
  1841.           memset(&str, 0, sizeof(str));
  1842.           /* */
  1843.           str.err_msg = buff_err_msg;
  1844.           str.filename = savename;
  1845.           str.mime = r.contenttype;
  1846.           str.url_host = urladr;
  1847.           str.url_file = urlfil;
  1848.           str.size = (int) r.size;
  1849.           /* */
  1850.           str.addLink = htsAddLink;
  1851.           /* */
  1852.           str.liens = liens;
  1853.           str.opt = &opt;
  1854.           str.sback = sback;
  1855.           str.cache = &cache;
  1856.           str.hashptr = hashptr;
  1857.           str.numero_passe = numero_passe;
  1858.           str.add_tab_alloc = add_tab_alloc;
  1859.           /* */
  1860.           str.lien_tot_ = &lien_tot;
  1861.           str.ptr_ = &ptr;
  1862.           str.lien_size_ = &lien_size;
  1863.           str.lien_buffer_ = &lien_buffer;
  1864.           /* Parse if recognized */
  1865.           switch(hts_parse_externals(&str)) {
  1866.           case 1:
  1867.             if ((opt.debug>1) && (opt.log!=NULL)) {
  1868.               fspc(opt.log,"debug"); fprintf(opt.log,"(External module): parsed successfully %s"LF,savename); test_flush;
  1869.             }
  1870.             break;
  1871.           case 0:
  1872.             if ((opt.debug>1) && (opt.log!=NULL)) {
  1873.               fspc(opt.log,"debug"); fprintf(opt.log,"(External module): couldn't parse successfully %s : %s"LF,savename, str.err_msg); test_flush;
  1874.             }
  1875.             break;
  1876.           }
  1877.         }
  1878.              
  1879.         
  1880.       }  // text/html ou autre
  1881.       
  1882.  
  1883.       /* Post-processing */
  1884.       if (fexist(savename)) {
  1885.         usercommand(&opt, 0, NULL, savename, urladr, urlfil);
  1886.       }
  1887.  
  1888.     }  // if !error
  1889.  
  1890. jump_if_done:
  1891.     // libΘrer les liens
  1892.     if (r.adr) { 
  1893.       freet(r.adr); 
  1894.       r.adr=NULL; 
  1895.     }   // libΘrer la mΘmoire!
  1896.     
  1897.     // prochain lien
  1898.     ptr++;
  1899.     
  1900.     // faut-il sauter le(s) lien(s) suivant(s)? (fichiers images α passer aprΦs les html)
  1901.     if (opt.getmode & 4) {    // sauver les non html aprΦs
  1902.       // sauter les fichiers selon la passe
  1903.       if (!numero_passe) {
  1904.         while((ptr<lien_tot)?(   liens[ptr]->pass2):0) ptr++;
  1905.       } else {
  1906.         while((ptr<lien_tot)?( ! liens[ptr]->pass2):0) ptr++;
  1907.       }
  1908.       if (ptr>=lien_tot) {     // fin de boucle
  1909.         if (!numero_passe) { // premiΦre boucle
  1910.           if ((opt.debug>1) && (opt.log!=NULL)) {
  1911.             fprintf(opt.log,LF"Now getting non-html files..."LF);
  1912.             test_flush;
  1913.           }
  1914.           numero_passe=1;   // seconde boucle
  1915.           ptr=0;
  1916.           // prochain pass2
  1917.           while((ptr<lien_tot)?(!liens[ptr]->pass2):0) ptr++;
  1918.           
  1919.           //printf("first link==%d\n");
  1920.           
  1921.         }
  1922.       }  
  1923.     }
  1924.  
  1925.     // copy abort state if necessary from outside
  1926.     if (!exit_xh && opt.state.exit_xh) {
  1927.       exit_xh=opt.state.exit_xh;
  1928.     }
  1929.     // a-t-on dΘpassΘ le quota?
  1930.     if (!back_checkmirror(&opt)) {
  1931.       ptr=lien_tot;
  1932.     } else if (exit_xh) {  // sortir
  1933.       if (opt.errlog) {
  1934.         fspc(opt.errlog,"info"); 
  1935.         if (exit_xh==1) {
  1936.           fprintf(opt.errlog,"Exit requested by shell or user"LF);
  1937.         } else {
  1938.           fprintf(opt.errlog,"Exit requested by engine"LF);
  1939.         }
  1940.         test_flush;
  1941.       } 
  1942.       ptr=lien_tot;
  1943.     }
  1944.   } while(ptr<lien_tot);
  1945.   //
  1946.   //
  1947.   //
  1948.   
  1949.   /*
  1950.   Ensure the index is being closed
  1951.   */
  1952.   HT_INDEX_END;
  1953.   
  1954.   /* 
  1955.     updating-a-remotely-deteted-website hack
  1956.     no much data transfered, no data saved
  1957.     <no files successfulyl saved>
  1958.     we assume that something was bad (no connection)
  1959.     just backup old cache and restore everything
  1960.   */
  1961.   if (
  1962.     (HTS_STAT.stat_files <= 0) 
  1963.     && 
  1964.     (HTS_STAT.HTS_TOTAL_RECV < 32768)    /* should be fine */
  1965.     ) {
  1966.     if (opt.errlog) {
  1967.       fspc(opt.errlog,"info"); fprintf(opt.errlog,"No data seems to have been transfered during this session! : restoring previous one!"LF);
  1968.       test_flush;
  1969.     } 
  1970.     XH_uninit;
  1971.     if ( (fexist(fconcat(opt.path_log,"hts-cache/old.dat"))) && (fexist(fconcat(opt.path_log,"hts-cache/old.ndx"))) ) {
  1972.       remove(fconcat(opt.path_log,"hts-cache/new.dat"));
  1973.       remove(fconcat(opt.path_log,"hts-cache/new.ndx"));
  1974.       remove(fconcat(opt.path_log,"hts-cache/new.lst"));
  1975.       remove(fconcat(opt.path_log,"hts-cache/new.txt"));
  1976.       rename(fconcat(opt.path_log,"hts-cache/old.dat"),fconcat(opt.path_log,"hts-cache/new.dat"));
  1977.       rename(fconcat(opt.path_log,"hts-cache/old.ndx"),fconcat(opt.path_log,"hts-cache/new.ndx"));
  1978.       rename(fconcat(opt.path_log,"hts-cache/old.lst"),fconcat(opt.path_log,"hts-cache/new.lst"));
  1979.       rename(fconcat(opt.path_log,"hts-cache/old.txt"),fconcat(opt.path_log,"hts-cache/new.txt"));
  1980.     }
  1981.     exit_xh=2;        /* interrupted (no connection detected) */
  1982.     return 1;
  1983.   }
  1984.  
  1985.   // info text  
  1986.   if (cache.txt) {
  1987.     fclose(cache.txt); cache.txt=NULL;
  1988.   }
  1989.  
  1990.   // purger!
  1991.   if (cache.lst) {
  1992.     fclose(cache.lst); cache.lst=NULL;
  1993.     if (opt.delete_old) {
  1994.       FILE *old_lst,*new_lst;
  1995.       //
  1996. #if HTS_ANALYSTE
  1997.       _hts_in_html_parsing=3;
  1998. #endif
  1999.       //
  2000.       old_lst=fopen(fconcat(opt.path_log,"hts-cache/old.lst"),"rb");
  2001.       if (old_lst) {
  2002.         LLint sz=fsize(fconcat(opt.path_log,"hts-cache/new.lst"));
  2003.         new_lst=fopen(fconcat(opt.path_log,"hts-cache/new.lst"),"rb");
  2004.         if ((new_lst) && (sz>0)) {
  2005.           char* adr=(char*) malloct((INTsys)sz);
  2006.           if (adr) {
  2007.             if (fread(adr,1,(INTsys)sz,new_lst) == sz) {
  2008.               char line[1100];
  2009.               int purge=0;
  2010.               while(!feof(old_lst)) {
  2011.                 linput(old_lst,line,1000);
  2012.                 if (!strstr(adr,line)) {    // fichier non trouvΘ dans le nouveau?
  2013.                   char BIGSTK file[HTS_URLMAXSIZE*2];
  2014.                   strcpybuff(file,opt.path_html);
  2015.                   strcatbuff(file,line+1);
  2016.                   file[strlen(file)-1]='\0';
  2017.                   if (fexist(file)) {       // toujours sur disque: virer
  2018.                     if (opt.log) {
  2019.                       fspc(opt.log,"info"); fprintf(opt.log,"Purging %s"LF,file);
  2020.                     }
  2021.                     remove(file); purge=1;
  2022.                   }
  2023.                 }
  2024.               }
  2025.               {
  2026.                 fseek(old_lst,0,SEEK_SET);
  2027.                 while(!feof(old_lst)) {
  2028.                   linput(old_lst,line,1000);
  2029.                   while(strnotempty(line) && (line[strlen(line)-1]!='/') && (line[strlen(line)-1]!='\\')) {
  2030.                     line[strlen(line)-1]='\0';
  2031.                   }
  2032.                   if (strnotempty(line))
  2033.                     line[strlen(line)-1]='\0';
  2034.                   if (strnotempty(line))
  2035.                     if (!strstr(adr,line)) {    // non trouvΘ?
  2036.                       char BIGSTK file[HTS_URLMAXSIZE*2];
  2037.                       strcpybuff(file,opt.path_html);
  2038.                       strcatbuff(file,line+1);
  2039.                       while ((strnotempty(file)) && (rmdir(file)==0)) {    // ok, ΘliminΘ (existait)
  2040.                         purge=1;
  2041.                         if (opt.log) {
  2042.                           fspc(opt.log,"info"); fprintf(opt.log,"Purging directory %s/"LF,file);
  2043.                           while(strnotempty(file) && (file[strlen(file)-1]!='/') && (file[strlen(file)-1]!='\\')) {
  2044.                             file[strlen(file)-1]='\0';
  2045.                           }
  2046.                           if (strnotempty(file))
  2047.                             file[strlen(file)-1]='\0';
  2048.                         }
  2049.                       }
  2050.                     }
  2051.                 }
  2052.               }
  2053.               //
  2054.               if (!purge) {
  2055.                 if (opt.log) {
  2056.                   fprintf(opt.log,"No files purged"LF);
  2057.                 }
  2058.               }
  2059.             }
  2060.             freet(adr);
  2061.           }
  2062.           fclose(new_lst);
  2063.         }
  2064.         fclose(old_lst);
  2065.       }
  2066.       //
  2067. #if HTS_ANALYSTE
  2068.       _hts_in_html_parsing=0;
  2069. #endif
  2070.     }
  2071.   }
  2072.   // fin purge!
  2073.  
  2074.   // Indexation
  2075.   if (opt.kindex)
  2076.     index_finish(opt.path_html,opt.kindex);
  2077.  
  2078.   // afficher rΘsumΘ dans log
  2079.   if (opt.log!=NULL) {
  2080.     char BIGSTK finalInfo[8192];
  2081.     int error   = fspc(NULL,"error");
  2082.     int warning = fspc(NULL,"warning");
  2083.     int info    = fspc(NULL,"info");
  2084.     char BIGSTK htstime[256];
  2085.     char BIGSTK infoupdated[256];
  2086.     // int n=(int) (stat_loaded/(time_local()-HTS_STAT.stat_timestart));
  2087.     LLint n=(LLint) (HTS_STAT.HTS_TOTAL_RECV/(max(1,time_local()-HTS_STAT.stat_timestart)));
  2088.     
  2089.     sec2str(htstime,time_local()-HTS_STAT.stat_timestart);
  2090.     //sprintf(finalInfo + strlen(finalInfo),LF"HTS-mirror complete in %s : %d links scanned, %d files written (%d bytes overall) [%d bytes received at %d bytes/sec]"LF,htstime,lien_tot-1,HTS_STAT.stat_files,stat_bytes,stat_loaded,n);
  2091.     infoupdated[0] = '\0';
  2092.     if (opt.is_update) {
  2093.       if (HTS_STAT.stat_updated_files > 0) {
  2094.         sprintf(infoupdated, ", %d files updated", (int)HTS_STAT.stat_updated_files);
  2095.       } else {
  2096.         sprintf(infoupdated, ", no files updated");
  2097.       }
  2098.     }
  2099.     finalInfo[0] = '\0';
  2100.     sprintf(finalInfo + strlen(finalInfo),
  2101.       "HTTrack Website Copier/"HTTRACK_VERSION" mirror complete in %s : "
  2102.       "%d links scanned, %d files written ("LLintP" bytes overall)%s "
  2103.       "["LLintP" bytes received at "LLintP" bytes/sec]",
  2104.       htstime,
  2105.       (int)lien_tot-1,
  2106.       (int)HTS_STAT.stat_files,
  2107.       (LLint)HTS_STAT.stat_bytes,
  2108.       infoupdated,
  2109.       (LLint)HTS_STAT.HTS_TOTAL_RECV,
  2110.       (LLint)n
  2111.       );
  2112.  
  2113.     if (HTS_STAT.total_packed > 0 && HTS_STAT.total_unpacked > 0) {
  2114.       int packed_ratio=(int)((LLint)(HTS_STAT.total_packed*100)/HTS_STAT.total_unpacked);
  2115.       sprintf(finalInfo + strlen(finalInfo),", "LLintP" bytes transfered using HTTP compression in %d files, ratio %d%%",(LLint)HTS_STAT.total_unpacked,HTS_STAT.total_packedfiles,(int)packed_ratio);
  2116.     }
  2117.     if (!opt.nokeepalive && HTS_STAT.stat_sockid > 0 && HTS_STAT.stat_nrequests > HTS_STAT.stat_sockid) {
  2118.       int rq = (HTS_STAT.stat_nrequests * 10) / HTS_STAT.stat_sockid;
  2119.       sprintf(finalInfo + strlen(finalInfo),", %d.%d requests per connection", rq/10, rq%10);
  2120.     }
  2121.     sprintf(finalInfo + strlen(finalInfo),LF);
  2122.     if (error)
  2123.       sprintf(finalInfo + strlen(finalInfo),"(%d errors, %d warnings, %d messages)"LF,error,warning,info);
  2124.     else
  2125.       sprintf(finalInfo + strlen(finalInfo),"(No errors, %d warnings, %d messages)"LF,warning,info);
  2126.  
  2127.     // Log
  2128.     fprintf(opt.log,LF"%s", finalInfo);
  2129.  
  2130.     // Close ZIP
  2131.     if (cache.zipOutput) {
  2132.       zipClose(cache.zipOutput, finalInfo);
  2133.       cache.zipOutput = NULL;
  2134.     }
  2135.     
  2136.     test_flush;
  2137.   }
  2138. #if DEBUG_HASH
  2139.   // noter les collisions
  2140.   {
  2141.     int i;
  2142.     int empty1=0,empty2=0,empty3=0;
  2143.     for(i=0;i<HTS_HASH_SIZE;i++) {
  2144.       if (hash.hash[0][i] == -1)
  2145.         empty1++;
  2146.       if (hash.hash[1][i] == -1)
  2147.         empty2++;
  2148.       if (hash.hash[2][i] == -1)
  2149.         empty3++;
  2150.     }
  2151.     printf("\n");
  2152.     printf("Debug info: Hash-table report\n");
  2153.     printf("Number of files entered:   %d\n",hashnumber);
  2154.     printf("Table size:                %d\n",HTS_HASH_SIZE);
  2155.     printf("\n");
  2156.     printf("Longest chain sav:              %d, empty: %d\n",longest_hash[0],empty1);
  2157.     printf("Longest chain adr,fil:          %d, empty: %d\n",longest_hash[1],empty2);
  2158.     printf("Longest chain former_adr/fil:   %d, empty: %d\n",longest_hash[2],empty3);
  2159.     printf("\n");
  2160.   }
  2161. #endif    
  2162.   // fin afficher rΘsumΘ dans log
  2163.  
  2164.   // ending
  2165.   usercommand(&opt,0,NULL,NULL,NULL,NULL);
  2166.  
  2167.   // dΘsallocation mΘmoire & buffers
  2168.   XH_uninit;
  2169.  
  2170.   return 1;    // OK
  2171. }
  2172. // version 2 pour le reste
  2173. // flusher si on doit lire peu α peu le fichier
  2174. #undef test_flush
  2175. #define test_flush if (opt->flush) { fflush(opt->log); fflush(opt->errlog); }
  2176.  
  2177.  
  2178. // Estimate transfer rate
  2179. // a little bit complex, but not too much
  2180. /*
  2181.   .. : idle
  2182.   ^  : event
  2183.  
  2184.   ----|----|----|----|----|----|----|----|---->
  2185.    1    2    3    4    5    6    7    8    9   time (seconds)
  2186.   ----|----|----|----|----|----|----|----|---->
  2187.   ^........^.........^.........^.........^.... timer 0
  2188.   ----^.........^.........^.........^......... timer 1
  2189.            0    1    0    1    0    1    0     timer N sets its statistics
  2190.       *         *         *         *          timer 0 resync timer 1
  2191.  
  2192.   Therefore, each seconds, we resync the transfer rate with 2-seconds
  2193.  
  2194. */
  2195. int engine_stats(void) {
  2196. #if 0
  2197.   static FILE* debug_fp=NULL; /* ok */
  2198.   if (!debug_fp)
  2199.     debug_fp=fopen("esstat.txt","wb");
  2200. #endif
  2201.   HTS_STAT.stat_nsocket=HTS_STAT.stat_errors=HTS_STAT.nbk=0;
  2202.   HTS_STAT.nb=0;
  2203.   if (HTS_STAT.HTS_TOTAL_RECV>2048) {
  2204.     TStamp cdif=mtime_local();
  2205.     int i;
  2206.  
  2207.     for(i=0;i<2;i++) {
  2208.       if ( (cdif - HTS_STAT.istat_timestart[i]) >= 2000) {
  2209.         TStamp dif;
  2210. #if 0
  2211. fprintf(debug_fp,"set timer %d\n",i); fflush(debug_fp);
  2212. #endif
  2213.         dif=cdif - HTS_STAT.istat_timestart[i];
  2214.         if ((TStamp)(dif/1000)>0) {
  2215.           LLint byt=(HTS_STAT.HTS_TOTAL_RECV - HTS_STAT.istat_bytes[i]);
  2216.           HTS_STAT.rate=(LLint)((TStamp) ((TStamp)byt/(dif/1000)));
  2217.           HTS_STAT.istat_idlasttimer=i;      // this timer recently sets the stats
  2218.           //
  2219.           HTS_STAT.istat_bytes[i]=HTS_STAT.HTS_TOTAL_RECV;
  2220.           HTS_STAT.istat_timestart[i]=cdif;
  2221.         }
  2222.         return 1;       /* refreshed */
  2223.       }
  2224.     }
  2225.  
  2226.     // resynchronization between timer 0 (master) and 1 (slave)
  2227.     // timer #0 resync timer #1 when reaching 1 second limit
  2228.     if (HTS_STAT.istat_reference01 != HTS_STAT.istat_timestart[0]) {
  2229.       if ( (cdif - HTS_STAT.istat_timestart[0]) >= 1000) {
  2230. #if 0
  2231. fprintf(debug_fp,"resync timer 1\n"); fflush(debug_fp);
  2232. #endif
  2233.         HTS_STAT.istat_bytes[1]=HTS_STAT.HTS_TOTAL_RECV;
  2234.         HTS_STAT.istat_timestart[1]=cdif;
  2235.         HTS_STAT.istat_reference01=HTS_STAT.istat_timestart[0];
  2236.       }
  2237.     }
  2238.  
  2239.   }
  2240.   return 0;
  2241. }
  2242.  
  2243.  
  2244. #define _FILTERS     (*opt->filters.filters)
  2245. #define _FILTERS_PTR (opt->filters.filptr)
  2246. #define _ROBOTS      ((robots_wizard*)opt->robotsptr)
  2247.  
  2248. // bannir host (trop lent etc)
  2249. void host_ban(httrackp* opt,lien_url** liens,int ptr,int lien_tot,struct_back* sback,char* host) {
  2250.   lien_back* const back = sback->lnk;
  2251.   const int back_max = sback->count;
  2252.   //int l;
  2253.   int i;
  2254.  
  2255.   if (host[0]=='!')
  2256.     return;    // erreur.. dΘja cancellΘ.. bizarre.. devrait pas arriver
  2257.  
  2258.   /* sanity check */
  2259.   if (*_FILTERS_PTR + 1 >= opt->maxfilter) {
  2260.     opt->maxfilter += HTS_FILTERSINC;
  2261.     if (filters_init(&_FILTERS, opt->maxfilter, HTS_FILTERSINC) == 0) {
  2262.       printf("PANIC! : Too many filters : >%d [%d]\n",*_FILTERS_PTR,__LINE__);
  2263.       if (opt->errlog) {
  2264.         fprintf(opt->errlog,LF"Too many filters, giving up..(>%d)"LF,*_FILTERS_PTR);
  2265.         fprintf(opt->errlog,"To avoid that: use #F option for more filters (example: -#F5000)"LF);
  2266.         fflush(opt->errlog);
  2267.       }
  2268.       assertf("too many filters - giving up" == NULL);
  2269.     }
  2270.   }
  2271.  
  2272.   // interdire host
  2273.   assertf((*_FILTERS_PTR) < opt->maxfilter);
  2274.   if (*_FILTERS_PTR < opt->maxfilter) {
  2275.     strcpybuff(_FILTERS[*_FILTERS_PTR],"-");
  2276.     strcatbuff(_FILTERS[*_FILTERS_PTR],host);
  2277.     strcatbuff(_FILTERS[*_FILTERS_PTR],"/*");     // host/ * interdit
  2278.     (*_FILTERS_PTR)++; 
  2279.   }
  2280.   
  2281.   // oups
  2282.   if (strlen(host)<=1) {    // euhh?? longueur <= 1
  2283.     if (strcmp(host,"file://")) {
  2284.       //## if (host[0]!=lOCAL_CHAR) {  // pas local
  2285.       if (opt->log!=NULL) {
  2286.         fprintf(opt->log,"PANIC! HostCancel detected memory leaks [char %d]"LF,host[0]); test_flush;
  2287.       }          
  2288.       return;  // purΘe
  2289.     }
  2290.   }
  2291.   
  2292.   // couper connexion
  2293.   for(i=0;i<back_max;i++) {
  2294.     if (back[i].status>=0)    // rΘception OU prΩt
  2295.       if (strfield2(back[i].url_adr,host)) {
  2296. #if HTS_DEBUG_CLOSESOCK
  2297.         DEBUG_W("host control: deletehttp\n");
  2298. #endif
  2299.         back[i].status=0;  // terminΘ
  2300.         back_set_finished(sback, i);
  2301.         if (back[i].r.soc!=INVALID_SOCKET) deletehttp(&back[i].r);
  2302.         back[i].r.soc=INVALID_SOCKET;
  2303.         back[i].r.statuscode=STATUSCODE_TIMEOUT;    // timeout (peu importe si c'est un traffic jam)
  2304.         strcpybuff(back[i].r.msg,"Link Cancelled by host control");
  2305.         
  2306.         if ((opt->debug>1) && (opt->log!=NULL)) {
  2307.           fprintf(opt->log,"Shutdown: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2308.         }          
  2309.       }
  2310.   }
  2311.   
  2312.   // effacer liens
  2313.   //l=strlen(host);
  2314.   for(i=0;i<lien_tot;i++) {
  2315.     //if (liens[i]->adr_len==l) {    // mΩme taille de chaεne
  2316.     // Calcul de taille sΘcurisΘe
  2317.     if (liens[i]) {
  2318.       if (liens[i]->adr) {
  2319.         int l = 0;
  2320.         while((liens[i]->adr[l]) && (l<1020)) l++;
  2321.         if ((l > 0) && (l<1020)) {   // sΘcuritΘ
  2322.           if (strfield2(jump_identification(liens[i]->adr),host)) {    // host
  2323.             if ((opt->debug>1) && (opt->log!=NULL)) {
  2324.               fprintf(opt->log,"Cancel: %s%s"LF,liens[i]->adr,liens[i]->fil); test_flush;
  2325.             }
  2326.             strcpybuff(liens[i]->adr,"!");    // cancel (invalide hash)
  2327.             // on efface pas le hash, because si on rencontre le lien, reverif sav..
  2328.           }
  2329.         } else {
  2330.           if (opt->log!=NULL) {
  2331.             char dmp[1040];
  2332.             dmp[0]='\0';
  2333.             strncatbuff(dmp,liens[i]->adr,1024);
  2334.             fprintf(opt->log,"WARNING! HostCancel detected memory leaks [len %d at %d]"LF,l,i); test_flush;
  2335.             fprintf(opt->log,"dump 1024 bytes (address %p): "LF"%s"LF,liens[i]->adr,dmp); test_flush;
  2336.           }          
  2337.         }
  2338.       } else {
  2339.         if (opt->log!=NULL) {
  2340.           fprintf(opt->log,"WARNING! HostCancel detected memory leaks [adr at %d]"LF,i); test_flush;
  2341.         }  
  2342.       }
  2343.     } else {
  2344.       if (opt->log!=NULL) {
  2345.         fprintf(opt->log,"WARNING! HostCancel detected memory leaks [null at %d]"LF,i); test_flush;
  2346.       }  
  2347.     }
  2348.     //}
  2349.   }
  2350. }
  2351.  
  2352.  
  2353. #if 0
  2354. /* Init structure */
  2355. /* 1 : init */
  2356. /* -1 : off */
  2357. /* 0 : query */
  2358. /* 2 : LOCK */
  2359. /* -2 : UNLOCK */
  2360. void* structcheck_init(int init) {
  2361.   int structcheck_size = 1024;
  2362.   inthash structcheck_hash=NULL;
  2363.   /* */
  2364.   static PTHREAD_LOCK_TYPE structcheck_init_mutex;
  2365.   static int structcheck_init_mutex_init=0;
  2366.  
  2367.   if (init == 1 || init == -1) {
  2368.     if (init) {
  2369.       if (structcheck_hash)
  2370.         inthash_delete(&structcheck_hash);
  2371.       structcheck_hash=NULL;
  2372.     }
  2373.     if (init != -1) {
  2374.       if (structcheck_init_mutex_init == 0) {
  2375.         htsSetLock(&structcheck_init_mutex, -999);
  2376.         structcheck_init_mutex_init=1;
  2377.       }
  2378.       if (structcheck_hash==NULL) {
  2379.         structcheck_hash=inthash_new(structcheck_size);  // dΘsallouΘ xh_xx
  2380.       }
  2381.     }
  2382.   }
  2383.  
  2384.   /* Lock / Unlock */
  2385.   if (init == 2) {  // Lock
  2386.     htsSetLock(&structcheck_init_mutex, 1);
  2387.   } else if (init == -2) {  // Unlock
  2388.     htsSetLock(&structcheck_init_mutex, 0);
  2389.   }
  2390.   return structcheck_hash;
  2391. }
  2392. #endif
  2393.  
  2394. int filters_init(char*** ptrfilters, int maxfilter, int filterinc) {
  2395.   char** filters = *ptrfilters;
  2396.   int filter_max=maximum(maxfilter, 128);
  2397.   if (filters == NULL) {
  2398.     filters=(char**) malloct( sizeof(char*) * (filter_max+2) );
  2399.     memset(filters, 0, sizeof(char*) * (filter_max+2));  // filters[0] == 0
  2400.   } else {
  2401.     filters=(char**) realloct(filters, sizeof(char*) * (filter_max+2) );
  2402.   }
  2403.   if (filters) {
  2404.     if (filters[0] == NULL) {
  2405.       filters[0]=(char*) malloct( sizeof(char) * (filter_max+2) * (HTS_URLMAXSIZE*2) );
  2406.       memset(filters[0], 0, sizeof(char) * (filter_max+2) * (HTS_URLMAXSIZE*2) );
  2407.     } else {
  2408.       filters[0]=(char*) realloct(filters[0], sizeof(char) * (filter_max+2) * (HTS_URLMAXSIZE*2) );
  2409.     }
  2410.     if (filters[0] == NULL) {
  2411.       freet(filters);
  2412.       filters = NULL;
  2413.     }
  2414.   }
  2415.   if (filters != NULL) {
  2416.     int i;
  2417.     int from;
  2418.     if (filterinc == 0)
  2419.       from = 0;
  2420.     else
  2421.       from = filter_max - filterinc;
  2422.     for(i=0 ; i<=filter_max ; i++) {    // PLUS UN (sΘcuritΘ)
  2423.       filters[i]=filters[0]+i*(HTS_URLMAXSIZE*2);
  2424.     }
  2425.     for(i=from ; i<=filter_max ; i++) {    // PLUS UN (sΘcuritΘ)
  2426.       filters[i][0]='\0';    // clear
  2427.     }
  2428.   }
  2429.   *ptrfilters = filters;
  2430.   return (filters != NULL) ? filter_max : 0;
  2431. }
  2432.  
  2433. // vΘrifier prΘsence de l'arbo
  2434. HTSEXT_API int structcheck(char* s) {
  2435.   // vΘrifier la prΘsence des dossier(s)
  2436.   char *a=s;
  2437.   char BIGSTK nom[HTS_URLMAXSIZE*2];
  2438.   char *b;
  2439.   //inthash structcheck_hash=NULL;
  2440.   if (strnotempty(s)==0) return 0;
  2441.   if (strlen(s)>HTS_URLMAXSIZE) return 0;
  2442.  
  2443.   // Get buffer address
  2444.   /*
  2445.   structcheck_hash = (inthash)structcheck_init(0);
  2446.   if (structcheck_hash == NULL) {
  2447.     return -1;
  2448.   }
  2449.   */
  2450.  
  2451.   b=nom;
  2452.   do {    
  2453.     if (*a) *b++=*a++;
  2454.     while((*a!='/') && (*a!='\0')) *b++=*a++;
  2455.     *b='\0';    // pas de ++ pour boucler
  2456.     if (*a=='/') {    // toujours dossier
  2457.       if (strnotempty(nom)) {         
  2458.         //if (inthash_write(structcheck_hash, nom, 1)) {    // non encore crΘΘ                       
  2459. #if HTS_WIN
  2460.         if (mkdir(fconv(nom))!=0)
  2461. #else    
  2462.           if (mkdir(fconv(nom),HTS_ACCESS_FOLDER)!=0)
  2463. #endif
  2464.           {
  2465. #if HTS_REMOVE_ANNOYING_INDEX
  2466.             // might be a filename with same name than this folder
  2467.             // then, remove it to allow folder creation
  2468.             // it happends when servers gives a folder index while
  2469.             // requesting / page
  2470.             // -> if the file can be opened (not a folder) then rename it
  2471.             if (fexist(fconv(nom))) {
  2472.               rename(fconv(nom),fconcat(fconv(nom),".txt"));
  2473.             }
  2474.             // if it fails, that's too bad
  2475. #if HTS_WIN
  2476.             mkdir(fconv(nom));
  2477. #else    
  2478.             mkdir(fconv(nom),HTS_ACCESS_FOLDER);
  2479. #endif
  2480. #endif
  2481.             // Si existe dΘja renvoie une erreur.. tant pis
  2482.           }
  2483. #if HTS_WIN==0
  2484.           /*chmod(fconv(nom),HTS_ACCESS_FOLDER);*/
  2485. #endif
  2486.           //}
  2487.       }
  2488.       *b++=*a++;    // slash
  2489.     } 
  2490.   } while(*a);
  2491.   return 0;
  2492. }
  2493.  
  2494.  
  2495. // sauver un fichier
  2496. int filesave(httrackp* opt,char* adr,int len,char* s,char* url_adr,char* url_fil) {
  2497.   FILE* fp;
  2498.   // Θcrire le fichier
  2499.   if ((fp=filecreate(s))!=NULL) {
  2500.     int nl=0;
  2501.     if (len>0) {
  2502.       nl=(int) fwrite(adr,1,(INTsys)len,fp);
  2503.     }
  2504.     fclose(fp);
  2505.     if (nl!=len)  // erreur
  2506.       return -1;
  2507.   } else
  2508.     return -1;
  2509.   
  2510.   return 0;
  2511. }
  2512.  
  2513. /* We should stop */
  2514. int check_fatal_io_errno(void) {
  2515.   switch(errno) {
  2516. #ifdef EMFILE
  2517.   case EMFILE: /* Too many open files */
  2518. #endif
  2519. #ifdef ENOSPC
  2520.   case ENOSPC: /* No space left on device */
  2521. #endif
  2522. #ifdef EROFS
  2523.   case EROFS:  /* Read-only file system */
  2524. #endif
  2525.     return 1;
  2526.     break;
  2527.   }
  2528.   return 0;
  2529. }
  2530.  
  2531.  
  2532. // ouvrir un fichier (avec chemin Un*x)
  2533. FILE* filecreate(char* s) {
  2534.   char BIGSTK fname[HTS_URLMAXSIZE*2];
  2535.   FILE* fp;
  2536.   fname[0]='\0';
  2537.  
  2538.   // noter lst
  2539.   filenote(s,NULL);
  2540.   
  2541.   // if (*s=='/') strcpybuff(fname,s+1); else strcpybuff(fname,s);    // pas de / (root!!) // ** SIIIIIII!!! α cause de -O <path>
  2542.   strcpybuff(fname,s);
  2543.  
  2544. #if HTS_DOSNAME
  2545.   // remplacer / par des slash arriΦre
  2546.   {
  2547.     int i=0;
  2548.     while(fname[i]) {
  2549.       if (fname[i]=='/')
  2550.         fname[i]='\\';
  2551.       i++;
  2552.     } 
  2553.   } 
  2554.   // a partir d'ici le slash devient antislash
  2555. #endif
  2556.   
  2557.   // ouvrir
  2558.   fp=fopen(fname,"wb");
  2559.   if (fp == NULL) {
  2560.     // construire le chemin si besoin est
  2561.     (void)structcheck(s);
  2562.     fp=fopen(fname,"wb");
  2563.   }
  2564.   
  2565. #if HTS_WIN==0
  2566.   if (fp!=NULL) chmod(fname,HTS_ACCESS_FILE);
  2567. #endif
  2568.  
  2569.   return fp;
  2570. }
  2571.  
  2572. // ouvrir un fichier (avec chemin Un*x)
  2573. FILE* fileappend(char* s) {
  2574.   char BIGSTK fname[HTS_URLMAXSIZE*2];
  2575.   FILE* fp;
  2576.   fname[0]='\0';
  2577.  
  2578.   // noter lst
  2579.   filenote(s,NULL);
  2580.   
  2581.   // if (*s=='/') strcpybuff(fname,s+1); else strcpybuff(fname,s);    // pas de / (root!!) // ** SIIIIIII!!! α cause de -O <path>
  2582.   strcpybuff(fname,s);
  2583.  
  2584. #if HTS_DOSNAME
  2585.   // remplacer / par des slash arriΦre
  2586.   {
  2587.     int i=0;
  2588.     while(fname[i]) {
  2589.       if (fname[i]=='/')
  2590.         fname[i]='\\';
  2591.       i++;
  2592.     } 
  2593.   } 
  2594.   // a partir d'ici le slash devient antislash
  2595. #endif
  2596.   
  2597.   // ouvrir
  2598.   fp=fopen(fname,"ab");
  2599.   
  2600. #if HTS_WIN==0
  2601.   if (fp!=NULL) chmod(fname,HTS_ACCESS_FILE);
  2602. #endif
  2603.  
  2604.   return fp;
  2605. }
  2606.  
  2607.  
  2608. // create an empty file
  2609. int filecreateempty(char* filename) {
  2610.   FILE* fp;
  2611.   fp=filecreate(filename);      // filenote & co
  2612.   if (fp) {
  2613.     fclose(fp);
  2614.     return 1;
  2615.   } else
  2616.     return 0; 
  2617. }
  2618.  
  2619. // noter fichier
  2620. typedef struct {
  2621.   FILE* lst;
  2622.   char path[HTS_URLMAXSIZE*2];
  2623. } filenote_strc;
  2624. int filenote(char* s,filecreate_params* params) {
  2625.   filenote_strc* strc;
  2626.   NOSTATIC_RESERVE(strc, filenote_strc, 1);
  2627.   
  2628.   // gestion du fichier liste liste
  2629.   if (params) {
  2630.     //filecreate_params* p = (filecreate_params*) params;
  2631.     strcpybuff(strc->path,params->path);
  2632.     strc->lst=params->lst;
  2633.     return 0;
  2634.   } else if (strc->lst) {
  2635.     char BIGSTK savelst[HTS_URLMAXSIZE*2];
  2636.     strcpybuff(savelst,fslash(s));
  2637.     // couper chemin?
  2638.     if (strnotempty(strc->path)) {
  2639.       if (strncmp(fslash(strc->path),savelst,strlen(strc->path))==0) {  // couper
  2640.         strcpybuff(savelst,s+strlen(strc->path));
  2641.       }
  2642.     }
  2643.     fprintf(strc->lst,"[%s]"LF,savelst);
  2644.     fflush(strc->lst);
  2645.   }
  2646.   return 1;
  2647. }
  2648.  
  2649. void file_notify(char* adr,char* fil,char* save,int create,int modify,int not_updated) {
  2650. #if HTS_ANALYSTE
  2651.   if (hts_htmlcheck_filesave2 != NULL) {
  2652.     hts_htmlcheck_filesave2(adr, fil, save, create, modify, not_updated);
  2653.   }
  2654. #endif
  2655. }
  2656.  
  2657. // executer commande utilisateur
  2658. static void postprocess_file(httrackp* opt,char* save, char* adr, char* fil);
  2659. typedef struct {
  2660.   int exe;
  2661.   char cmd[2048];
  2662. } usercommand_strc;
  2663. HTS_INLINE void usercommand(httrackp* opt,int _exe,char* _cmd,char* file,char* adr,char* fil) {
  2664.   usercommand_strc* strc;
  2665.   NOSTATIC_RESERVE(strc, usercommand_strc, 1);
  2666.   
  2667.   /* Callback */
  2668.   if (_exe) {
  2669.     strcpybuff(strc->cmd,_cmd);
  2670.     if (strnotempty(strc->cmd))
  2671.       strc->exe=_exe;
  2672.     else
  2673.       strc->exe=0;
  2674.   }
  2675.  
  2676.   /* post-processing */
  2677.   postprocess_file(opt, file, adr, fil);
  2678.  
  2679. #if HTS_ANALYSTE
  2680.   if (hts_htmlcheck_filesave != NULL) {
  2681.     if (file != NULL && strnotempty(file))
  2682.       hts_htmlcheck_filesave(file);
  2683.   }
  2684. #endif
  2685.  
  2686.   if (strc->exe) {
  2687.     if (file != NULL && strnotempty(file)) {
  2688.       if (strnotempty(strc->cmd)) {
  2689.         usercommand_exe(strc->cmd,file);
  2690.       }
  2691.     }
  2692.   }
  2693. }
  2694. void usercommand_exe(char* cmd,char* file) {
  2695.   char BIGSTK temp[8192];
  2696.   char c[2]="";
  2697.   int i;
  2698.   temp[0]='\0';
  2699.   //
  2700.   for(i=0;i<(int) strlen(cmd);i++) {
  2701.     if ((cmd[i]=='$') && (cmd[i+1]=='0')) {
  2702.       strcatbuff(temp,file);
  2703.       i++;
  2704.     } else {
  2705.       c[0]=cmd[i]; c[1]='\0';
  2706.       strcatbuff(temp,c);
  2707.     }
  2708.   }
  2709.   system(temp);
  2710. }
  2711.  
  2712.  
  2713. static void postprocess_file(httrackp* opt,char* save, char* adr, char* fil) {
  2714.   int first = 0;
  2715.   /* MIME-html archive to build */
  2716.   if (opt != NULL && opt->mimehtml) {
  2717.     if (adr != NULL && strcmp(adr, "primary") == 0) {
  2718.       adr = NULL;
  2719.     }
  2720.     if (save != NULL && opt != NULL && adr != NULL && adr[0] && strnotempty(save) && fexist(save)) {
  2721.       char* rsc_save = save;
  2722.       char* rsc_fil = strrchr(fil, '/');
  2723.       int n;
  2724.       if (rsc_fil == NULL)
  2725.         rsc_fil = fil;
  2726.       if (strncmp(fslash(save), fslash(opt->path_html), (n = (int)strlen(opt->path_html))) == 0) {
  2727.         rsc_save += n;
  2728.       }
  2729.  
  2730.       if (!opt->state.mimehtml_created) {
  2731.         first = 1;
  2732.         opt->state.mimefp = fopen(fconcat(opt->path_html,"index.mht"), "wb");
  2733.         if (opt->state.mimefp != NULL) {
  2734.           char BIGSTK rndtmp[1024], currtime[256];
  2735.           srand(time(NULL));
  2736.           time_gmt_rfc822(currtime);
  2737.           sprintf(rndtmp, "%d_%d", (int)time(NULL), (int) rand());
  2738.           sprintf(opt->state.mimemid, "----=_MIMEPart_%s_=----", rndtmp);
  2739.           fprintf(opt->state.mimefp, "From: HTTrack Website Copier <nobody@localhost>\r\n"
  2740.             "Subject: Local mirror\r\n"
  2741.             "Date: %s\r\n"
  2742.             "Message-ID: <httrack_%s@localhost>\r\n"
  2743.             "Content-Type: multipart/related;\r\n"
  2744.             "\tboundary=\"%s\";\r\n"
  2745.             "\ttype=\"text/html\"\r\n"
  2746.             "MIME-Version: 1.0\r\n"
  2747.             "\r\nThis message is a RFC MIME-compliant multipart message.\r\n"
  2748.             "\r\n"
  2749.             , currtime, rndtmp, opt->state.mimemid);
  2750.           opt->state.mimehtml_created = 1;
  2751.         } else {
  2752.           opt->state.mimehtml_created = -1;
  2753.           if ( opt->errlog != NULL ) {
  2754.             fspc(opt->errlog,"error"); fprintf(opt->log,"unable to create index.mht"LF);
  2755.           }
  2756.         }
  2757.       }
  2758.       if (opt->state.mimehtml_created == 1 && opt->state.mimefp != NULL) {
  2759.         FILE* fp = fopen(save, "rb");
  2760.         if (fp != NULL) {
  2761.           char buff[60*100 + 2];
  2762.           char mimebuff[256];
  2763.           char BIGSTK cid[HTS_URLMAXSIZE*3];
  2764.           int len;
  2765.           int isHtml = ( ishtml(save) == 1 );
  2766.           mimebuff[0] = '\0';
  2767.  
  2768.           /* CID */
  2769.           strcpybuff(cid, adr);
  2770.           strcatbuff(cid, fil);
  2771.           escape_in_url(cid);
  2772.           { char* a = cid; while((a = strchr(a, '%'))) { *a = 'X'; a++; } }
  2773.           
  2774.           guess_httptype(mimebuff, save);
  2775.           fprintf(opt->state.mimefp, "--%s\r\n", opt->state.mimemid);
  2776.           /*if (first)
  2777.           fprintf(opt->state.mimefp, "Content-disposition: inline\r\n");
  2778.           else*/
  2779.           fprintf(opt->state.mimefp, "Content-disposition: attachment; filename=\"%s\"\r\n", rsc_save);
  2780.           fprintf(opt->state.mimefp, 
  2781.             "Content-Type: %s\r\n"
  2782.             "Content-Transfer-Encoding: %s\r\n"
  2783.             /*"Content-Location: http://localhost/%s\r\n"*/
  2784.             "Content-ID: <%s>\r\n"
  2785.             "\r\n"
  2786.             , mimebuff
  2787.             , isHtml ? "8bit" : "base64"
  2788.             /*, rsc_save*/
  2789.             , cid);
  2790.           while((len = fread(buff, 1, sizeof(buff) - 2, fp)) > 0) {
  2791.             buff[len] = '\0';
  2792.             if (!isHtml) {
  2793.               char base64buff[60*100*2];
  2794.               code64((unsigned char*)buff, len, (unsigned char*)base64buff, 1);
  2795.               fprintf(opt->state.mimefp, "%s", base64buff);
  2796.             } else {
  2797.               fprintf(opt->state.mimefp, "%s", buff);
  2798.             }
  2799.           }
  2800.           fclose(fp);
  2801.           fprintf(opt->state.mimefp, "\r\n\r\n");
  2802.         }
  2803.       }
  2804.     } else if (save == NULL) {
  2805.       if (opt->state.mimehtml_created == 1 && opt->state.mimefp != NULL) {
  2806.         fprintf(opt->state.mimefp, 
  2807.           "--%s--\r\n", opt->state.mimemid);
  2808.         fclose(opt->state.mimefp);
  2809.         opt->state.mimefp = NULL;
  2810.       }
  2811.     }
  2812.   }
  2813. }
  2814.  
  2815. // Θcrire n espaces dans fp
  2816. typedef struct {
  2817.   int error;
  2818.   int warning;
  2819.   int info;
  2820. } fspc_strc;
  2821. HTS_INLINE int fspc(FILE* fp,char* type) {
  2822.   fspc_strc* strc;
  2823.   NOSTATIC_RESERVE(strc, fspc_strc, 1); // log..
  2824.  
  2825.   //
  2826.   if (fp) {
  2827.     char s[256];
  2828.     time_t tt;
  2829.     struct tm* A;
  2830.     tt=time(NULL);
  2831.     A=localtime(&tt);
  2832.     if (A == NULL) {
  2833.       int localtime_returned_null=0;
  2834.       assert(localtime_returned_null);
  2835.     }
  2836.     strftime(s,250,"%H:%M:%S",A);
  2837.     if (strnotempty(type))
  2838.       fprintf(fp,"%s\t%c%s: \t",s,hichar(*type),type+1);
  2839.     else
  2840.       fprintf(fp,"%s\t \t",s);
  2841.     if (strcmp(type,"warning")==0)
  2842.       strc->warning++;
  2843.     else if (strcmp(type,"error")==0)
  2844.       strc->error++;
  2845.     else if (strcmp(type,"info")==0)
  2846.       strc->info++;
  2847.   } 
  2848.   else if (!type)
  2849.     strc->error=strc->warning=strc->info=0;     // reset
  2850.   else if (strcmp(type,"warning")==0)
  2851.     return strc->warning;
  2852.   else if (strcmp(type,"error")==0)
  2853.     return strc->error;
  2854.   else if (strcmp(type,"info")==0)
  2855.     return strc->info;
  2856.   return 0;
  2857. }
  2858.  
  2859.  
  2860. // vΘrifier taux de transfert
  2861. #if 0
  2862. void check_rate(TStamp stat_timestart,int maxrate) {
  2863.   // vΘrifier taux de transfert (pas trop grand?)
  2864.   /*
  2865.   if (maxrate>0) {
  2866.     int r = (int) (HTS_STAT.HTS_TOTAL_RECV/(time_local()-stat_timestart));    // taux actuel de transfert
  2867.     HTS_STAT.HTS_TOTAL_RECV_STATE=0;
  2868.     if (r>maxrate) {    // taux>taux autorisΘ
  2869.       int taux = (int) (((TStamp) (r - maxrate) * 100) / (TStamp) maxrate);
  2870.       if (taux<15)
  2871.         HTS_STAT.HTS_TOTAL_RECV_STATE=1;   // ralentir un peu (<15% dΘpassement)
  2872.       else if (taux<50)
  2873.         HTS_STAT.HTS_TOTAL_RECV_STATE=2;   // beaucoup (<50% dΘpassement)
  2874.       else
  2875.         HTS_STAT.HTS_TOTAL_RECV_STATE=3;   // ΘnormΘment (>50% dΘpassement)
  2876.     }
  2877.   }
  2878.   */
  2879. }
  2880. #endif
  2881.  
  2882. // ---
  2883. // sous routines liΘes au moteur et au backing
  2884.  
  2885. // supplemental links ready (done) after ptr or ready in background
  2886. int backlinks_done(struct_back* sback,lien_url** liens,int lien_tot,int ptr) {
  2887.   int n=0;
  2888. #if 0
  2889.   int i;
  2890.   //Links done and stored in cache
  2891.   for(i=ptr+1;i<lien_tot;i++) {
  2892.     if (liens[i]) {
  2893.       if (liens[i]->pass2 == -1) {
  2894.         n++;
  2895.       }
  2896.     }
  2897.   }
  2898. #else
  2899.   // finalized in background
  2900.   n+=HTS_STAT.stat_background;
  2901. #endif
  2902.   n+=back_done_incache(sback);
  2903.   return n;
  2904. }
  2905.  
  2906. // remplir backing si moins de max_bytes en mΘmoire
  2907. HTS_INLINE int back_fillmax(struct_back* sback,httrackp* opt,cache_back* cache,lien_url** liens,int ptr,int numero_passe,int lien_tot) {
  2908.   if (!opt->state.stop) {
  2909.     if (back_incache(sback)<opt->maxcache) {  // pas trop en mΘmoire?
  2910.       return back_fill(sback,opt,cache,liens,ptr,numero_passe,lien_tot);
  2911.     }
  2912.   }
  2913.   return -1;                /* plus de place */
  2914. }
  2915.  
  2916. int back_pluggable_sockets_strict(struct_back* sback, httrackp* opt) {
  2917.   lien_back* const back = sback->lnk;
  2918.   const int back_max = sback->count;
  2919.   int n = opt->maxsoc - back_nsoc(sback);
  2920.  
  2921.   // connect limiter
  2922.   if (n > 0 && opt->maxconn > 0 && HTS_STAT.last_connect > 0) {
  2923.     TStamp opTime = HTS_STAT.last_request ? HTS_STAT.last_request : HTS_STAT.last_connect;
  2924.     TStamp cTime = mtime_local();
  2925.     TStamp lap = ( cTime - opTime );
  2926.     TStamp minLap = (TStamp) ( 1000.0 / opt->maxconn );
  2927.     if (lap < minLap) {
  2928.       n = 0;
  2929.     } else {
  2930.       int nMax = (int) ( lap / minLap );
  2931.       n = min(n, nMax);
  2932.     }
  2933.   }
  2934.  
  2935.   return n;
  2936. }
  2937.  
  2938. int back_pluggable_sockets(struct_back* sback, httrackp* opt) {
  2939.   lien_back* const back = sback->lnk;
  2940.   const int back_max = sback->count;
  2941.   int n;
  2942.  
  2943.   // ajouter autant de socket qu'on peut ajouter
  2944.   n=back_pluggable_sockets_strict(sback, opt);
  2945.  
  2946.   // vΘrifier qu'il restera assez de place pour les tests ensuite (en thΘorie, 1 entrΘe libre restante suffirait)
  2947.   n=min( n, back_available(sback) - 8 );
  2948.  
  2949.   // no space left on backing stack - do not back anymore
  2950.   if (back_stack_available(sback) <= 2)
  2951.     n=0;
  2952.  
  2953.   return n;
  2954. }
  2955.  
  2956. // remplir backing
  2957. int back_fill(struct_back* sback,httrackp* opt,cache_back* cache,lien_url** liens,int ptr,int numero_passe,int lien_tot) {
  2958.   lien_back* const back = sback->lnk;
  2959.   const int back_max = sback->count;
  2960.   int n = back_pluggable_sockets(sback, opt);
  2961.   if (opt->savename_delayed == 2 && !opt->delayed_cached)  /* cancel (always delayed) */
  2962.     return 0;
  2963.   if (n>0) {
  2964.     int p;
  2965.  
  2966.     if (ptr<cache->ptr_last) {      /* restart (2 scans: first html, then non html) */
  2967.       cache->ptr_ant=0;
  2968.     }
  2969.  
  2970.     p=ptr+1;
  2971.     /* on a dΘja parcouru */
  2972.     if (p<cache->ptr_ant)
  2973.       p=cache->ptr_ant;
  2974.     while( (p<lien_tot) && (n>0) && back_checkmirror(opt)) {
  2975.     //while((p<lien_tot) && (n>0) && (p < ptr+opt->maxcache_anticipate)) {
  2976.       int ok=1;
  2977.       
  2978.       // on ne met pas le fichier en backing si il doit Ωtre traitΘ aprΦs
  2979.       if (liens[p]->pass2) {  // 2Φ passe
  2980.         if (numero_passe!=1)
  2981.           ok=0;
  2982.       } else {
  2983.         if (numero_passe!=0)
  2984.           ok=0;
  2985.       }
  2986.       
  2987.       // note: si un backing est fini, il reste en mΘmoire jusqu'α ce que
  2988.       // le ptr l'atteigne
  2989.       if (ok) {
  2990.                 int index = back_index(sback, liens[p]->adr,liens[p]->fil,liens[p]->sav);
  2991.         if (index < 0) {
  2992.           if (back_add(sback,opt,cache,liens[p]->adr,liens[p]->fil,liens[p]->sav,liens[liens[p]->precedent]->adr,liens[liens[p]->precedent]->fil,liens[p]->testmode,&liens[p]->pass2)==-1) {
  2993.             if ( (opt->debug>1) && (opt->errlog!=NULL) ) {
  2994.               fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: unable to add more links through back_add for back_fill"LF);
  2995.               test_flush;
  2996.             }                    
  2997. #if BDEBUG==1
  2998.             printf("error while adding\n");
  2999. #endif                  
  3000.             n=0;    // sortir
  3001.           } else {
  3002.             n--;
  3003. #if BDEBUG==1
  3004.             printf("backing: %s%s\n",liens[p]->adr,liens[p]->fil);          
  3005. #endif
  3006.           } 
  3007.                 } else {
  3008.                     back_set_passe2_ptr(opt,cache,sback,index,&liens[p]->pass2);
  3009.                 }
  3010.       }
  3011.       p++;
  3012.     }  // while
  3013.     /* sauver position derniΦre anticipation */
  3014.     cache->ptr_ant=p;
  3015.     cache->ptr_last=ptr;
  3016.   }
  3017.   return 0;
  3018. }
  3019. // ---
  3020.  
  3021.  
  3022.  
  3023.  
  3024.  
  3025.  
  3026.  
  3027.  
  3028.  
  3029.  
  3030.  
  3031.  
  3032.  
  3033.  
  3034.  
  3035.  
  3036.  
  3037.  
  3038. // routines de dΘtournement de SIGHUP & co (Unix)
  3039. //
  3040. httrackp* hts_declareoptbuffer(httrackp* optdecl) {
  3041.   static httrackp* opt=NULL; /* OK */
  3042.   if (optdecl) opt=optdecl;
  3043.   return opt;
  3044. }
  3045. //
  3046. void sig_finish( int code ) {       // finir et quitter
  3047.   signal(code,sig_term);  // quitter si encore
  3048.   exit_xh=1;
  3049.   fprintf(stderr,"\nExit requested to engine (signal %d)\n",code);
  3050. }
  3051. void sig_term( int code ) {       // quitter brutalement
  3052.   fprintf(stderr,"\nProgram terminated (signal %d)\n",code);
  3053.   exit(0);
  3054. }
  3055. #if HTS_WIN
  3056. void sig_ask( int code ) {        // demander
  3057.   char s[256];
  3058.   signal(code,sig_term);  // quitter si encore
  3059.   printf("\nQuit program/Interrupt/Cancel? (Q/I/C) ");
  3060.   fflush(stdout);
  3061.   scanf("%s",s);
  3062.   if ( (s[0]=='y') || (s[0]=='Y') || (s[0]=='o') || (s[0]=='O') || (s[0]=='q') || (s[0]=='Q'))
  3063.     exit(0);     // quitter
  3064.   else if ( (s[0]=='i') || (s[0]=='I') ) {
  3065.     httrackp* opt=hts_declareoptbuffer(NULL);
  3066.     if (opt) {
  3067.       // ask for stop
  3068.       opt->state.stop=1;
  3069.     }
  3070.   }
  3071.   signal(code,sig_ask);  // remettre signal
  3072. }
  3073. #else
  3074. void sig_back( int code ) {       // ignorer et mettre en backing 
  3075.   signal(code,sig_ignore);
  3076.   sig_doback(0);
  3077. }
  3078. void sig_ask( int code ) {        // demander
  3079.   char s[256];
  3080.   signal(code,sig_term);  // quitter si encore
  3081.   printf("\nQuit program/Interrupt/Background/bLind background/Cancel? (Q/I/B/L/C) ");
  3082.   fflush(stdout);
  3083.   scanf("%s",s);
  3084.   if ( (s[0]=='y') || (s[0]=='Y') || (s[0]=='o') || (s[0]=='O') || (s[0]=='q') || (s[0]=='Q'))
  3085.     exit(0);     // quitter
  3086.   else if ( (s[0]=='b') || (s[0]=='B') || (s[0]=='a') || (s[0]=='A') )
  3087.     sig_doback(0);  // arriΦre plan
  3088.   else if ( (s[0]=='l') || (s[0]=='L') )
  3089.     sig_doback(1);  // arriΦre plan
  3090.   else if ( (s[0]=='i') || (s[0]=='I') ) {
  3091.     httrackp* opt=hts_declareoptbuffer(NULL);
  3092.     if (opt) {
  3093.       // ask for stop
  3094.       printf("finishing pending transfers.. please wait\n");
  3095.       opt->state.stop=1;
  3096.     }
  3097.     signal(code,sig_ask);  // remettre signal
  3098.   }
  3099.   else {
  3100.     printf("cancel..\n");
  3101.     signal(code,sig_ask);  // remettre signal
  3102.   }
  3103. }
  3104. void sig_ignore( int code ) {     // ignorer signal
  3105. }
  3106. void sig_brpipe( int code ) {     // treat if necessary
  3107.   signal(code, sig_brpipe);
  3108. }
  3109. void sig_doback(int blind) {       // mettre en backing 
  3110.   int out=-1;
  3111.   //
  3112.   printf("\nMoving into background to complete the mirror...\n"); fflush(stdout);
  3113.  
  3114.   {
  3115.     httrackp* opt=hts_declareoptbuffer(NULL);
  3116.     if (opt) {
  3117.       // suppress logging and asking lousy questions
  3118.       opt->quiet=1;
  3119.       opt->verbosedisplay=0;
  3120.     }
  3121.   }
  3122.  
  3123.   if (!blind)
  3124.     out = open("hts-nohup.out",O_CREAT|O_WRONLY,S_IRUSR|S_IWUSR);
  3125.   if (out == -1)
  3126.     out = open("/dev/null",O_WRONLY,S_IRUSR|S_IWUSR);
  3127.   close(0);
  3128.   close(1);
  3129.   dup(out);
  3130.   close(2);
  3131.   dup(out);
  3132.   //
  3133.   switch (fork()) {
  3134.   case 0: 
  3135.     break;
  3136.   case -1:
  3137.     fprintf(stderr,"Error: can not fork process\n");
  3138.     break;
  3139.   default:            // pere
  3140.     usleep(100000);   // pause 1/10s "A  microsecond  is  .000001s"
  3141.     _exit(0);
  3142.     break;  
  3143.   }
  3144. }
  3145. #endif
  3146. // fin routines de dΘtournement de SIGHUP & co
  3147.  
  3148. // Poll stdin.. si besoin
  3149. #if HTS_POLL
  3150. // lecture stdin des caractΦres disponibles
  3151. int read_stdin(char* s,int max) {
  3152.   int i=0;
  3153.   while((check_stdin()) && (i<(max-1)) )
  3154.     s[i++]=fgetc(stdin);
  3155.   s[i]='\0';
  3156.   return i;
  3157. }
  3158. #ifdef _WIN32
  3159. HTS_INLINE int check_stdin(void) {
  3160. #ifndef _WIN32_WCE
  3161.   return (_kbhit());
  3162. #else
  3163.   return 0;
  3164. #endif
  3165. }
  3166. #else
  3167. HTS_INLINE int check_flot(T_SOC s) {
  3168.   fd_set fds;
  3169.   struct timeval tv;
  3170.   FD_ZERO(&fds);
  3171.   FD_SET((T_SOC) s,&fds);
  3172.   tv.tv_sec=0;
  3173.   tv.tv_usec=0;
  3174.   select(s+1,&fds,NULL,NULL,&tv);
  3175.   return FD_ISSET(s,&fds);
  3176. }
  3177. HTS_INLINE int check_stdin(void) {
  3178.   fflush(stdout); fflush(stdin);
  3179.   if (check_flot(0))
  3180.     return 1;
  3181.   return 0;
  3182. }
  3183. #endif
  3184. #endif
  3185.  
  3186. HTS_INLINE int check_sockerror(T_SOC s) {
  3187.   fd_set fds;
  3188.   struct timeval tv;
  3189.   FD_ZERO(&fds);
  3190.   FD_SET((T_SOC) s,&fds);
  3191.   tv.tv_sec=0;
  3192.   tv.tv_usec=0;
  3193.   select(s+1,NULL,NULL,&fds,&tv);
  3194.   return FD_ISSET(s,&fds);
  3195. }
  3196.  
  3197. /* check incoming data */
  3198. HTS_INLINE int check_sockdata(T_SOC s) {
  3199.   fd_set fds;
  3200.   struct timeval tv;
  3201.   FD_ZERO(&fds);
  3202.   FD_SET((T_SOC) s,&fds);
  3203.   tv.tv_sec=0;
  3204.   tv.tv_usec=0;
  3205.   select(s+1,&fds,NULL,NULL,&tv);
  3206.   return FD_ISSET(s,&fds);
  3207. }
  3208.  
  3209. // Attente de touche
  3210. #if HTS_ANALYSTE
  3211. int ask_continue(void) {
  3212.   char* s;
  3213.   s=hts_htmlcheck_query2(HTbuff);
  3214.   if (s) {
  3215.     if (strnotempty(s)) {
  3216.       if ((strfield2(s,"N")) || (strfield2(s,"NO")) || (strfield2(s,"NON")))
  3217.         return 0;
  3218.     }
  3219.     return 1;
  3220.   }
  3221.   return 1;
  3222. }
  3223. #else
  3224. int ask_continue(void) {
  3225.   char s[12];
  3226.   s[0]='\0';
  3227.   printf("Press <Y><Enter> to confirm, <N><Enter> to abort\n");
  3228.   io_flush; linput(stdin,s,4);
  3229.   if (strnotempty(s)) {
  3230.     if ((strfield2(s,"N")) || (strfield2(s,"NO")) || (strfield2(s,"NON")))
  3231.       return 0;
  3232.   }
  3233.   return 1;
  3234. }
  3235. #endif
  3236.  
  3237. // nombre de digits dans un nombre
  3238. int nombre_digit(int n) {
  3239.   int i=1;
  3240.   while(n >= 10) { n/=10; i++; }
  3241.   return i;
  3242. }
  3243.  
  3244.  
  3245. // renvoi adresse de la fin du token dans p
  3246. // renvoi NULL si la chaine est un token unique
  3247. // (PATCHE Θgalement la chaine)
  3248. // ex: "test" "test2" renvoi adresse sur espace
  3249. // flag==1 si chaine comporte des echappements comme \"
  3250. char* next_token(char* p,int flag) {
  3251.   int detect=0;
  3252.   int quote=0;
  3253.   p--;
  3254.   do {
  3255.     p++;
  3256.     if (flag && (*p=='\\')) {   // sauter \x ou \"
  3257.       if (quote) {
  3258.         char c='\0';
  3259.         if (*(p+1)=='\\')
  3260.           c='\\';
  3261.         else if (*(p+1)=='"')
  3262.           c='"';
  3263.         if (c) {
  3264.           char BIGSTK tempo[8192];
  3265.           tempo[0]=c; tempo[1]='\0';
  3266.           strcatbuff(tempo,p+2);
  3267.           strcpybuff(p,tempo);
  3268.         }
  3269.       }
  3270.     }
  3271.     else if (*p==34) {  // guillemets (de fin)
  3272.       char BIGSTK tempo[8192];
  3273.       tempo[0]='\0';
  3274.       strcatbuff(tempo,p+1);
  3275.       strcpybuff(p,tempo);   /* wipe "" */
  3276.       p--;
  3277.       /* */
  3278.       quote=!quote;
  3279.     }
  3280.     else if (*p==32) {
  3281.       if (!quote)
  3282.         detect=1;
  3283.     }
  3284.     else if (*p=='\0') {
  3285.       p=NULL;
  3286.       detect=1;
  3287.     }
  3288.   } while(!detect);
  3289.   return p;
  3290. }
  3291.  
  3292. // routines annexes 
  3293. #if HTS_ANALYSTE
  3294. // canceller un fichier (noter comme cancellable)
  3295. // !!NOT THREAD SAFE!!
  3296. HTSEXT_API char* hts_cancel_file(char * s) {
  3297.   static char sav[HTS_URLMAXSIZE*2]="";
  3298.   if (s[0]!='\0')
  3299.   if (sav[0]=='\0')
  3300.     strcpybuff(sav,s);
  3301.   return sav;
  3302. }
  3303. HTSEXT_API void hts_cancel_test(void) {
  3304.   if (_hts_in_html_parsing==2)
  3305.     _hts_cancel=2;
  3306. }
  3307. HTSEXT_API void hts_cancel_parsing(void) {
  3308.   if (_hts_in_html_parsing)
  3309.    _hts_cancel=1;
  3310. }
  3311. #endif
  3312. //        for(_i=0;(_i<back_max) && (index<NStatsBuffer);_i++) {
  3313. //          i=(back_index+_i)%back_max;    // commencer par le "premier" (l'actuel)
  3314. //          if (back[i].status>=0) {     // signifie "lien actif"
  3315.  
  3316. #if 0
  3317. /*  
  3318. hts_add_file, add/get elements in the add chain for java parsing
  3319. if file_position >= 0
  3320.   push 'file/file_position'
  3321.   return 1 (return 0 if exists)
  3322. else
  3323.   pop file -> 'file'
  3324.   return 'file_position'
  3325. else if empty/error
  3326.   return -1;
  3327. */
  3328. typedef struct addfile_chain {
  3329.   char name[1024];
  3330.   int pos;
  3331.   struct addfile_chain* next;
  3332. } addfile_chain;
  3333. typedef addfile_chain* addfile_chain_ptr;
  3334. int opt->(char* file,int file_position) {
  3335.   addfile_chain** chain;
  3336.   NOSTATIC_RESERVE(chain, addfile_chain_ptr, 1);
  3337.  
  3338.   if (file_position>=0) {         /* copy file to the chain */
  3339.     struct addfile_chain** current;
  3340.     current=chain;                     /* start from */
  3341.     while(*current) {
  3342.       if (strcmp((*current)->name,file)==0)
  3343.         return 0;                       /* already exists */
  3344.       current=&( (*current)->next );    /* 'next' address */
  3345.     }
  3346.     *current=calloct(1,sizeof(addfile_chain));
  3347.     if (*current) {
  3348.       (*current)->next=NULL;
  3349.       (*current)->pos=-1;
  3350.       (*current)->name[0]='\0';
  3351.     }
  3352.     if (*current) {
  3353.       strcpybuff((*current)->name,file);
  3354.       (*current)->pos=file_position;
  3355.       return 1;
  3356.     } else {
  3357.       printf("PANIC! Too many Java files during parsing [1]\n");
  3358.       return -1;
  3359.     }
  3360.   } else {                      /* copy last element in file and delete it */
  3361.     if (file)
  3362.       file[0]='\0';
  3363.     if (*chain) {
  3364.       struct addfile_chain** current;
  3365.       int pos=-1;
  3366.       current=chain;                     /* start from */
  3367.       while( (*current)->next ) {
  3368.         current=&( (*current)->next );    /* 'next' address */
  3369.       }
  3370.       if (file)
  3371.         strcpybuff(file,(*current)->name);
  3372.       pos=(*current)->pos;
  3373.       freet(*current);
  3374.       *current=NULL;
  3375.       return pos;
  3376.     }
  3377.     return -1;                            /* no more elements */
  3378.   }
  3379.  
  3380.   return 0;
  3381. }
  3382. #endif
  3383.  
  3384. #if HTS_ANALYSTE
  3385. // en train de parser un fichier html? rΘponse: % effectuΘs
  3386. // flag>0 : refresh demandΘ
  3387. HTSEXT_API int hts_is_parsing(int flag) {
  3388.   if (_hts_in_html_parsing) {  // parsing?
  3389.     if (flag>=0) _hts_in_html_poll=1;  // faudrait un tit refresh
  3390.     return max(_hts_in_html_done,1); // % effectuΘs
  3391.   } else {
  3392.     return 0;                 // non
  3393.   }
  3394. }
  3395. HTSEXT_API int hts_is_testing(void) {            // 0 non 1 test 2 purge
  3396.   if (_hts_in_html_parsing==2)
  3397.     return 1;
  3398.   else if (_hts_in_html_parsing==3)
  3399.     return 2;
  3400.   else if (_hts_in_html_parsing==4)
  3401.     return 3;
  3402.   else if (_hts_in_html_parsing==5)   // scheduling
  3403.     return 4;
  3404.   else if (_hts_in_html_parsing==6)   // wait for slot
  3405.     return 5;
  3406.   return 0;
  3407. }
  3408. HTSEXT_API int hts_is_exiting(void) {
  3409.   return exit_xh;
  3410. }
  3411. // message d'erreur?
  3412. char* hts_errmsg(void) {
  3413.   return _hts_errmsg;
  3414. }
  3415. // mode pause transfer
  3416. HTSEXT_API int hts_setpause(int p) {
  3417.   if (p>=0) _hts_setpause=p;
  3418.   return _hts_setpause;
  3419. }
  3420. // ask for termination
  3421. HTSEXT_API int hts_request_stop(int force) {
  3422.   httrackp* opt=hts_declareoptbuffer(NULL);
  3423.   if (opt) {
  3424.     opt->state.stop=1;
  3425.   }
  3426.   return 0;
  3427. }
  3428. // rΘgler en cours de route les paramΦtres rΘglables..
  3429. // -1 : erreur
  3430. HTSEXT_API int hts_setopt(httrackp* set_opt) {
  3431.   if (set_opt) {
  3432.     httrackp* engine_opt=hts_declareoptbuffer(NULL);
  3433.     if (engine_opt) {
  3434.       //_hts_setopt=opt;
  3435.       copy_htsopt(set_opt,engine_opt);
  3436.     }
  3437.   }
  3438.   return 0;
  3439. }
  3440. // ajout d'URL
  3441. // -1 : erreur
  3442. HTSEXT_API int hts_addurl(char** url) {
  3443.   if (url) _hts_addurl=url;
  3444.   return (_hts_addurl!=NULL);
  3445. }
  3446. HTSEXT_API int hts_resetaddurl(void) {
  3447.   _hts_addurl=NULL;
  3448.   return (_hts_addurl!=NULL);
  3449. }
  3450. // copier nouveaux paramΦtres si besoin
  3451. HTSEXT_API int copy_htsopt(httrackp* from,httrackp* to) {
  3452.   if (from->maxsite > -1) 
  3453.     to->maxsite = from->maxsite;
  3454.   
  3455.   if (from->maxfile_nonhtml > -1) 
  3456.     to->maxfile_nonhtml = from->maxfile_nonhtml;
  3457.   
  3458.   if (from->maxfile_html > -1) 
  3459.     to->maxfile_html = from->maxfile_html;
  3460.   
  3461.   if (from->maxsoc > 0) 
  3462.     to->maxsoc = from->maxsoc;
  3463.   
  3464.   if (from->nearlink > -1) 
  3465.     to->nearlink = from->nearlink;
  3466.   
  3467.   if (from->timeout > -1) 
  3468.     to->timeout = from->timeout;
  3469.   
  3470.   if (from->rateout > -1)
  3471.     to->rateout = from->rateout;
  3472.   
  3473.   if (from->maxtime > -1) 
  3474.     to->maxtime = from->maxtime;
  3475.  
  3476. #if HTS_USEMMS
  3477.     if (from->mms_maxtime > -1)
  3478.     to->mms_maxtime = from->mms_maxtime;
  3479. #endif
  3480.  
  3481.   if (from->maxrate > -1)
  3482.     to->maxrate = from->maxrate;
  3483.   
  3484.   if (from->maxconn > 0)
  3485.     to->maxconn = from->maxconn;
  3486.  
  3487.   if (strnotempty(from->user_agent)) 
  3488.     strcpybuff(to->user_agent , from->user_agent);
  3489.   
  3490.   if (from->retry > -1) 
  3491.     to->retry = from->retry;
  3492.   
  3493.   if (from->hostcontrol > -1) 
  3494.     to->hostcontrol = from->hostcontrol;
  3495.   
  3496.   if (from->errpage > -1) 
  3497.     to->errpage = from->errpage;
  3498.  
  3499.   if (from->parseall > -1) 
  3500.     to->parseall = from->parseall;
  3501.  
  3502.  
  3503.   // test all: bit 8 de travel
  3504.   if (from->travel > -1)  {
  3505.     if (from->travel & 256)
  3506.       to->travel|=256;
  3507.     else
  3508.       to->travel&=255;
  3509.   }
  3510.  
  3511.  
  3512.   return 0;
  3513. }
  3514.  
  3515. #endif
  3516. //
  3517.  
  3518. /* External modules callback */
  3519. int htsAddLink(htsmoduleStruct* str, char* link) {
  3520.   if (link != NULL && str != NULL && link[0] != '\0') {
  3521.     ENGINE_LOAD_CONTEXT_BASE();
  3522.     /* */
  3523.     char BIGSTK adr[HTS_URLMAXSIZE*2],
  3524.       fil[HTS_URLMAXSIZE*2],
  3525.       save[HTS_URLMAXSIZE*2];
  3526.     char BIGSTK codebase[HTS_URLMAXSIZE*2];
  3527.     /* */
  3528.     int pass_fix, prio_fix;
  3529.     /* */
  3530.     int forbidden_url = 1;
  3531.     
  3532.     codebase[0]='\0';
  3533.     
  3534.     if ((opt->debug>1) && (opt->log!=NULL)) {
  3535.       fspc(opt->log,"debug"); fprintf(opt->log,"(module): adding link : '%s'"LF, link); test_flush;
  3536.     }
  3537.     // recopie de "creer le lien"
  3538.     //    
  3539.  
  3540. #if HTS_ANALYSTE
  3541.     if (hts_htmlcheck_linkdetected != NULL && !hts_htmlcheck_linkdetected(link)) {
  3542.       if (opt->errlog) {
  3543.         fspc(opt->errlog,"error"); fprintf(opt->errlog,"Link %s refused by external wrapper"LF, link);
  3544.         test_flush;
  3545.       }
  3546.       return 0;
  3547.     }
  3548.     if (hts_htmlcheck_linkdetected2 != NULL && !hts_htmlcheck_linkdetected2(link, NULL)) {
  3549.       if (opt->errlog) {
  3550.         fspc(opt->errlog,"error"); fprintf(opt->errlog,"Link %s refused by external wrapper(2)"LF, link);
  3551.         test_flush;
  3552.       }
  3553.       return 0;
  3554.     }
  3555. #endif
  3556.  
  3557.     // adr = c'est la mΩme
  3558.     // fil et save: save2 et fil2
  3559.     prio_fix=maximum(liens[ptr]->depth-1,0);
  3560.     pass_fix=max(liens[ptr]->pass2,numero_passe);
  3561.     if (liens[ptr]->cod) strcpybuff(codebase,liens[ptr]->cod);       // codebase valable pour tt les classes descendantes
  3562.     if (strnotempty(codebase)==0) {    // pas de codebase, construire
  3563.       char* a;
  3564.       if (str->relativeToHtmlLink == 0)
  3565.         strcpybuff(codebase,liens[ptr]->fil);
  3566.       else
  3567.         strcpybuff(codebase,liens[liens[ptr]->precedent]->fil);
  3568.       a=codebase+strlen(codebase)-1;
  3569.       while((*a) && (*a!='/') && ( a > codebase)) a--;
  3570.       if (*a=='/')
  3571.         *(a+1)='\0';    // couper
  3572.     } else {    // couper http:// Θventuel
  3573.       if (strfield(codebase,"http://")) {
  3574.         char BIGSTK tempo[HTS_URLMAXSIZE*2];
  3575.         char* a=codebase+7;
  3576.         a=strchr(a,'/');    // aprΦs host
  3577.         if (a) {  // ** msg erreur et vΘrifier?
  3578.           strcpybuff(tempo,a);
  3579.           strcpybuff(codebase,tempo);    // couper host
  3580.         } else {
  3581.           if (opt->errlog) {   
  3582.             fprintf(opt->errlog,"Unexpected strstr error in base %s"LF,codebase);
  3583.             test_flush;
  3584.           }
  3585.         }
  3586.       }
  3587.     }
  3588.     
  3589.     if (!((int) strlen(codebase)<HTS_URLMAXSIZE)) {    // trop long
  3590.       if (opt->errlog) {   
  3591.         fprintf(opt->errlog,"Codebase too long, parsing skipped (%s)"LF,codebase);
  3592.         test_flush;
  3593.       }
  3594.     }
  3595.     
  3596.     {
  3597.       char* lien = link;
  3598.       int dejafait=0;
  3599.       
  3600.       if (strnotempty(lien) && strlen(lien) < HTS_URLMAXSIZE) {
  3601.         
  3602.         // calculer les chemins et noms de sauvegarde
  3603.         if (ident_url_relatif(lien,urladr,codebase,adr,fil)>=0) { // reformage selon chemin
  3604.           int r;
  3605.           int set_prio_to = 0;
  3606.           int just_test_it = 0;
  3607.           forbidden_url = hts_acceptlink(opt, ptr, lien_tot, liens,
  3608.             adr,fil,
  3609.             NULL, NULL,
  3610.             &set_prio_to,
  3611.             &just_test_it);
  3612.           if ((opt->debug>1) && (opt->log!=NULL)) {
  3613.             fspc(opt->log,"debug"); fprintf(opt->log,"result for wizard external module link: %d"LF,forbidden_url);
  3614.             test_flush;
  3615.           }
  3616.  
  3617.           /* Link accepted */
  3618.           if (!forbidden_url) {
  3619.             char BIGSTK tempo[HTS_URLMAXSIZE*2];
  3620.             int a,b;
  3621.             tempo[0]='\0';
  3622.             a=opt->savename_type;
  3623.             b=opt->savename_83;
  3624.             opt->savename_type=0;
  3625.             opt->savename_83=0;
  3626.             // note: adr,fil peuvent Ωtre patchΘs
  3627.             r=url_savename(adr,fil,save,NULL,NULL,NULL,NULL,opt,liens,lien_tot,sback,cache,hashptr,ptr,numero_passe,NULL);
  3628.             // resolve unresolved type
  3629.             if (r != -1
  3630.               && forbidden_url == 0
  3631.               && IS_DELAYED_EXT(save)
  3632.               ) 
  3633.             {  // pas d'erreur, on continue
  3634.               char BIGSTK former_adr[HTS_URLMAXSIZE*2];
  3635.               char BIGSTK former_fil[HTS_URLMAXSIZE*2];
  3636.               former_adr[0] = former_fil[0] = '\0';
  3637.               r = hts_wait_delayed(str, adr, fil, save, former_adr, former_fil, &forbidden_url);
  3638.             }
  3639.             // end resolve unresolved type
  3640.             opt->savename_type=a;
  3641.             opt->savename_83=b;
  3642.             if (r != -1 && !forbidden_url) {
  3643.               if (savename) {
  3644.                 if (lienrelatif(tempo,save,savename)==0) {
  3645.                   if ((opt->debug>1) && (opt->log!=NULL)) {
  3646.                     fspc(opt->log,"debug"); fprintf(opt->log,"(module): relative link at %s build with %s and %s: %s"LF,adr,save,savename,tempo);
  3647.                     test_flush;
  3648.                     if (str->localLink && str->localLinkSize > (int) strlen(tempo) + 1) {
  3649.                       strcpybuff(str->localLink, tempo);
  3650.                     }
  3651.                   }
  3652.                 }
  3653.               }
  3654.             }
  3655.           }
  3656.  
  3657.           if (forbidden_url) {
  3658.             if ((opt->debug>1) && (opt->log!=NULL)) {
  3659.               fspc(opt->log,"debug"); fprintf(opt->log,"(module): file not caught: %s"LF,lien); test_flush;
  3660.             }
  3661.             if (str->localLink && str->localLinkSize > (int) ( strlen(adr) + strlen(fil) +  8 ) ) {
  3662.               str->localLink[0] = '\0';
  3663.               if (!link_has_authority(adr))
  3664.                 strcpybuff(str->localLink,"http://");
  3665.               strcatbuff(str->localLink, adr);
  3666.               strcatbuff(str->localLink, fil);
  3667.             }
  3668.             r=-1;
  3669.           }
  3670.  
  3671.           //
  3672.           if (r != -1) {
  3673.             if ((opt->debug>1) && (opt->log!=NULL)) {
  3674.               fspc(opt->log,"debug"); fprintf(opt->log,"(module): %s%s -> %s (base %s)"LF,adr,fil,save,codebase); test_flush;
  3675.             }
  3676.             
  3677.             // modifiΘ par rapport α l'autre version (cf prio_fix notamment et save2)
  3678.             
  3679.             // vΘrifier que le lien n'a pas dΘja ΘtΘ notΘ
  3680.             // si c'est le cas, alors il faut s'assurer que la prioritΘ associΘe
  3681.             // au fichier est la plus grande des deux prioritΘs
  3682.             //
  3683.             // On part de la fin et on essaye de se presser (Θconomise temps machine)
  3684.             {
  3685.               int i=hash_read(hashptr,save,"",0,opt->urlhack);      // lecture type 0 (sav)
  3686.               if (i>=0) {
  3687.                 liens[i]->depth=maximum(liens[i]->depth,prio_fix);
  3688.                 dejafait=1;
  3689.               }
  3690.             }         
  3691.             
  3692.             if (!dejafait) {
  3693.               //
  3694.               // >>>> CREER LE LIEN JAVA <<<<
  3695.               
  3696.               // enregistrer fichier (MACRO)
  3697.               liens_record(adr,fil,save,"","",opt->urlhack);
  3698.               if (liens[lien_tot]==NULL) {  // erreur, pas de place rΘservΘe
  3699.                 printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  3700.                 if (opt->errlog) { 
  3701.                   fprintf(opt->errlog,"Not enough memory, can not re-allocate %d bytes"LF,(int)((add_tab_alloc+1)*sizeof(lien_url)));
  3702.                   test_flush;
  3703.                 }
  3704.                 exit_xh=-1;    /* fatal error -> exit */
  3705.                 return 0;
  3706.               }  
  3707.               
  3708.               // mode test?                          
  3709.               liens[lien_tot]->testmode=0;          // pas mode test
  3710.               
  3711.               liens[lien_tot]->link_import=0;       // pas mode import
  3712.               
  3713.               // Θcrire autres paramΦtres de la structure-lien
  3714.               //if (meme_adresse)                                 
  3715.               liens[lien_tot]->premier=liens[ptr]->premier;
  3716.               //else    // sinon l'objet pΦre est le prΘcΘdent lui mΩme
  3717.               //  liens[lien_tot]->premier=ptr;
  3718.               
  3719.               liens[lien_tot]->precedent=ptr;
  3720.               // noter la prioritΘ
  3721.               if (!set_prio_to)
  3722.                 liens[lien_tot]->depth=prio_fix;
  3723.               else
  3724.                 liens[lien_tot]->depth=max(0,min(liens[ptr]->depth-1,set_prio_to-1));         // PRIORITE NULLE (catch page)
  3725.               liens[lien_tot]->pass2=max(pass_fix,numero_passe);
  3726.               liens[lien_tot]->retry=opt->retry;
  3727.               
  3728.               //strcpybuff(liens[lien_tot]->adr,adr);
  3729.               //strcpybuff(liens[lien_tot]->fil,fil);
  3730.               //strcpybuff(liens[lien_tot]->sav,save); 
  3731.               if ((opt->debug>1) && (opt->log!=NULL)) {
  3732.                 fspc(opt->log,"debug"); fprintf(opt->log,"(module): OK, NOTE: %s%s -> %s"LF,liens[lien_tot]->adr,liens[lien_tot]->fil,liens[lien_tot]->sav);
  3733.                 test_flush;
  3734.               }
  3735.               
  3736.               lien_tot++;  // UN LIEN DE PLUS
  3737.             }
  3738.           }
  3739.         }
  3740.       }
  3741.     }
  3742.     
  3743.     /* Apply changes */
  3744.     ENGINE_SAVE_CONTEXT_BASE();
  3745.  
  3746.     return (forbidden_url == 0);
  3747.   }
  3748.   return 0;
  3749. }
  3750.  
  3751.  
  3752.  
  3753.  
  3754.  
  3755. // message copyright interne
  3756. void voidf(void) {
  3757.   char* a;
  3758.   a=""CRLF""CRLF;
  3759.   a="+-----------------------------------------------+"CRLF;
  3760.   a="|HyperTextTRACKer, Offline Browser Utility      |"CRLF;
  3761.   a="|                      HTTrack Website Copier   |"CRLF;
  3762.   a="|Code:         Windows Interface Xavier Roche   |"CRLF;
  3763.   a="|                    HTS/HTTrack Xavier Roche   |"CRLF;
  3764.   a="|                .class Parser Yann Philippot   |"CRLF;
  3765.   a="|                                               |"CRLF;
  3766.   a="|Tested on:                 Windows95,98,NT,2K  |"CRLF;
  3767.   a="|                           Linux PC            |"CRLF;
  3768.   a="|                           Sun-Solaris 5.6     |"CRLF;
  3769.   a="|                           AIX 4               |"CRLF;
  3770.   a="|                                               |"CRLF;
  3771.   a="|Copyright (C) Xavier Roche and other           |"CRLF;
  3772.   a="|contributors                                   |"CRLF;
  3773.   a="|                                               |"CRLF;
  3774.   a="|Use this program at your own risks!            |"CRLF;    
  3775.   a="+-----------------------------------------------+"CRLF;
  3776.   a=""CRLF;
  3777. }
  3778.  
  3779.  
  3780. // HTTrack Website Copier Copyright (C) Xavier Roche and other contributors
  3781. //
  3782.  
  3783.